# coding: utf8


import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl


plt.rcParams['font.sans-serif'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False


class DemoDrawMode:

    def __init__(self):
        self.x = np.linspace(0, 10, 15)
        self.y = np.sin(self.x)
        self.z = np.cos(self.x)

    def draw_mode_1(self):
        # 1: matlab mode
        #    plt.subplot(ijk) to create new Figure and set to current subplot,
        #    or get subplot(ijk) to current subplot
        # plt.subplot(ijk)
        # plt.plot,pie,scatter,...

        plt.figure(figsize=(6, 3))
        plt.subplot(121)
        plt.plot(self.x, self.y)
        plt.subplot(122)
        plt.plot(self.x, self.z)
        plt.show()

    def draw_mode_2(self):
        # 2: Matlab-object
        #    plt.subplot to ax
        # ax = plt.subplot(ijk)
        # gh = ax.plot,scatter,...

        fig2 = plt.figure('mode-1', figsize=(12, 4))
        ax1 = plt.subplot(131)
        g1 = ax1.plot(self.x, self.y, color='green', linewidth=1.5, linestyle='--', marker='o', label='random')
        ax2 = plt.subplot(1, 3, 2)
        g2 = ax2.plot(self.x, np.cos(self.x), color='blue', linewidth=1.5, linestyle='-', marker='v', label='sin')
        ax3 = plt.subplot(1, 3, 3)
        g3 = ax3.pie([0.2, 0.3, 0.5])
        fig2.suptitle('matlab-object', fontsize=12)
        g1[0].set_color('r')
        print(
            f"Figure Object: fig2 = {fig2}\n"
            f"Axes[0]:  ax1 = {ax1}\n"
            f"Line2D Object in ax1: g1 = {str(g1)[2:str(g1).find(' at ')]}\n"
            f"Draw Object in ax2: g2 = {str(g2)[2:str(g2).find(' at ')]}\n"
            f"Draw Object in ax3: len(g3) = {len(g3)}\n"
            f"\t{[[str(do)[:str(do).find(' at ')] for do in g] for g in g3]}"
        )
        # fig2.show()

    def draw_mode_3(self):
        # 3: object-mode
        #    plt.axes to ax
        # ax = plt.axes([scale_coords])
        # ax.plot,...

        fig3 = plt.figure(2)
        ax1 = plt.axes([0.1, 0.2, 0.3, 0.5])
        ax1.plot(self.x, self.y, color='green', linewidth=1.5, linestyle='--', marker='o', label='random')
        ax2 = plt.axes([0.42, 0.71, 0.3, 0.2])
        ax2.plot(self.x, self.z, color='blue', linewidth=1.5, linestyle='-', marker='v', label='sin')
        fig3.suptitle('matlab-1', fontsize=12)
        # plt.show()

    def draw_mode_4(self):
        # 4: object-mode
        # fig, axs = subplots()
        # axs[].plot,...

        fig4, axs = plt.subplots(1, 2)
        axs[0].plot(self.x, self.y, color='green', linewidth=1.5, linestyle='--', marker='o', label='random')
        axs[1].plot(self.x, np.cos(self.x), color='blue', linewidth=1.5, linestyle='-', marker='v', label='sin')
        fig4.suptitle('matlab-3', fontsize=12)
        plt.show()
        print(
            f"AxesSubplot axs[0]: {axs[0]}"
        )

    def draw_mode_5(self):
        # 5: object-mode
        #    add_axes & get_axes
        # fig.add_axes([scale_coords])
        # axs = fig.get_axes()
        # axs[].plot,...

        fig5 = plt.figure(4, figsize=(8, 6))
        fig5.add_axes((0.1, 0.1, 0.5, 0.5), label='test1')
        fig5.add_axes([.6, 0.6, 0.3, 0.3], label='test2')
        axs = fig5.get_axes()
        axs[0].plot(self.x, self.y)
        axs[1].plot(self.x, self.y)
        # plt.show()

    def draw_mode_6(self):
        # 6: object-mode
        #    add_subplot & get_axes
        # fig.add_subplot(ijk)
        # axs = fig.get_axes(), axs[].plot...

        # multi integer augments
        fig61 = plt.figure(51)
        fig61.add_subplot(1, 2, 1, label='test1')
        fig61.add_subplot(1, 2, 2, label='test2')
        axs = fig61.get_axes()
        axs[0].plot(self.x, self.y)
        axs[1].plot(self.x, self.z)

        # single integer augment
        fig62 = plt.figure(52)
        fig62.add_subplot(121, label='test1')
        fig62.add_subplot(122, label='test2')
        axs = fig62.get_axes()
        axs[0].plot(self.x, self.y)
        axs[1].plot(self.x, self.z)
        plt.show()

    def draw_show(self):
        """
show(*, block=None)
    Display all open figures.

    In non-interactive mode, *block* defaults to True.  All figures
    will display and show will not return until all windows are closed.
    If there are no figures, return immediately.

    In interactive mode *block* defaults to False.  This will ensure
    that all of the figures are shown and this function immediately returns.

    Parameters
    ----------
    block : bool, optional

        If `True` block and run the GUI main loop until all windows
        are closed.

        If `False` ensure that all windows are displayed and return
        immediately.  In this case, you are responsible for ensuring
        that the event loop is running to have responsive figures.

    See Also
    --------
    ion : enable interactive mode
    ioff : disable interactive mode
        """
        fig, ax = plt.subplots()
        plt.show(block=False)       # Warning: will fail to return if block=True

    def draw_close(self):
        fig = plt.gca()
        print(fig)


class DemoExp:

    def __init__(self):
        # self.day = np.arange(0, 2, 0.12)
        # self.hightemp = np.cos(self.day)
        # self.a = [1, 2, 3]
        # climate_day = []
        # climate_night = []
        # with open('d:/project_skillful_python/ch5viz/data_climate_beijing_.txt', encoding='utf8') as fp:
        #     line_data = []
        #     day = -1
        #     for line in fp.readlines():
        #         if '日' in line:
        #             day = line[0:line.find('日')]
        #         if '白天' in line:
        #             if len(line_data) > 0:
        #                 climate_night.append(line_data)
        #                 line_data = []
        #             line_data.append(day)
        #         if '夜间' in line:
        #             climate_day.append(line_data)
        #             line_data = []
        #             line_data.append(day)
        #         if '温' in line:
        #             # line_data.append('maxtemp')
        #             line_data.append(int(line[line.find('温')+1:line.find('温')+3]))
        #         if 'hpa' in line.lower():
        #             # line_data.append('air_presure')
        #             line_data.append(int(line[0:line.find('h')]))
        #         if '%' in line:
        #             line_data.append(int(line[0:line.find('%')]))
        # # print(climate_day, '\n', climate_night)
        # climate = [x + [y[1]] for x, y in zip(climate_day, climate_night)]
        # # print(climate)
        # self.day = [v[0] for v in climate]
        # self.day = ['5.'+d if int(d) >= 28 else '6.'+d for d in self.day]
        # self.hightemp = [v[1] for v in climate]
        # self.lowtemp = [v[4] for v in climate]
        # self.pha = [v[2] for v in climate]
        # self.hum = [v[3] for v in climate]
        #
        # self.data = {'day': self.day,
        #              'high': self.hightemp,
        #              'low': self.lowtemp,
        #              'pha': self.pha,
        #              'hum': self.hum}

        self.data = {'date': ['5.28', '5.29', '5.30', '5.31', '6.1', '6.2', '6.3', '6.4', '6.5', '6.6', '6.7', '6.8',
                              '6.9', '6.10', '6.11', '6.12', '6.13', '6.14', '6.15', '6.16', '6.17', '6.18', '6.19',
                              '6.20', '6.21', '6.22', '6.23', '6.24', '6.25'],
                     'high': [16, 17, 20, 22, 24, 26, 27, 27, 28, 30, 29, 32, 33, 27, 25, 23, 21, 20, 25, 27, 28, 27,
                              29, 28, 29, 27, 28, 27, 29],
                     'low': [10, 12, 15, 16, 17, 17, 17, 15, 15, 16, 17, 17, 17, 15, 15, 16, 17, 12, 17, 15, 15, 16,
                             17, 17, 17, 15, 15, 16, 17],
                     'hpa': [998, 1001, 1001, 1001, 999, 1000, 999, 1001, 1001, 1001, 999, 1000, 999, 1001, 1001, 1001,
                             999, 1000, 999, 1001, 1001, 1001, 999, 1000, 999, 1001, 1001, 1001, 999],
                     'hum': [38, 44, 44, 67, 73, 37, 33, 44, 44, 67, 73, 37, 33, 44, 44, 67, 73, 37, 33, 44, 44, 67,
                             73, 37, 33, 44, 44, 67, 73]}

    def plot_line2d(self):
        # create Figure
        fig, axs = plt.subplots(3, 1, sharex='all')

        # plot data
        # data = {'day': self.day, 'hPa': self.pha, 'high': self.hightemp, 'low': self.lowtemp, 'hum': self.hum}
        data = self.data
        lines0 = axs[0].plot(data['date'], data['high'], 'go-',         # data is not supported
                             data['date'], data['low'], 'yX-')
        lines1 = axs[1].plot('date', 'hpa', 'kd-', data=data)
        lines2 = axs[2].plot('date', 'hum', data=data)

        # set in line2D object
        lines0[0].set(color='gray', linewidth=3, label='high')
        lines0[1].set(color='green', label='low')
        lines1[0].set_marker('o')
        lines1[0].set_linestyle('--')
        lines1[0].set_color('k')
        lines2[0].set(linewidth=5, marker='o', linestyle=':', color='m')

        # set xlim axs[0]
        axs[0].set(ylim=[0, 40],
                   title='high-low temperature',
                   ylabel='Celsius Degree')
        axs[1].set(ylim=[990, 1010],
                   title='air pressure',
                   ylabel='hPa')
        axs[2].set(ylim=[0, 100],
                   title='air humidity',
                   xlabel='Date',
                   ylabel='Humidity Ratio')
        # axs[0].yaxis.set_label('Celsius')   # no display
        # print([p for p in dir(axs[0].yaxis) if 'set' in p])
        # print([p for p in dir(axs[0]) if 'yaxis' in p or 'ylabel' in p])

        # set ticklabels
        axs[2].set_xticklabels(labels=data['date'], rotation=90)
        # for label in axs[1].get_xticklabels():
        #     label.set_rotation(60)

        # set legend
        axs[0].legend()

        plt.show()

    @staticmethod
    def plot_multi_axes_twin():
        from matplotlib.pyplot import MultipleLocator
        from matplotlib import ticker
        import pandas as pd

        data3 = pd.DataFrame({'sku_pri': [x**2 for x in range(25)],
                 'num_sales': [np.random.randint(1000000,40000000) for _ in range(25)],
                 'lk_num': [np.random.randint(100000,2000000) for _ in range(25)],
                 'lk_ra': [np.sin(x)*0.12 for x in range(25)],
                 })

        # 画多个图，传递多个不同的x轴刻度
        x = [i for i in range(25)]  # x轴标准刻度
        x1 = [i - 0.2 for i in range(25)]   # 第一个图x轴左偏移0.2
        x2 = [i + 0.2 for i in range(25)]   # 第二个图x周右偏移0.2，防止重叠
        x3 = [(v-12.5)/1.25*2*np.pi for v in x]
        xx = data3['sku_pri'].to_list()     # x周的刻度显示

        # 创建画板
        fig = plt.figure(figsize=(8, 5), dpi=80)
        plt.title('plt.plot()综合应用')

        # 第一个子图
        # ax = fig.add_subplot(1, 1, 1)
        ax = plt.gca()
        ax.set_ylabel('子图1-Y轴名称')
        ax.set_xlabel('子图1-X轴名字')
        ax.bar(x1, data3['num_sales'] / 10000, width=0.4, label='绘图一')
        ax.set_ylim(0, 4000)
        ax.set_xticks(ticks=x)  # x周刻度显示
        ax.set_xticklabels(xx)
        ax.legend(loc='upper left')

        # 第二个子图
        ax2 = ax.twinx()
        ax2.spines['right'].set_position(('axes', 1.0))
        ax2.set_ylabel('子图2-y轴名称')
        plt.bar(x2, data3['lk_num'] / 10000, width=0.4, color='orange', label='绘图二')
        plt.ylim(0, 200)
        plt.xticks(x, xx)
        ax2.legend(loc='upper center')

        # 第三个子图
        ax3 = ax.twinx()
        ax3.spines['right'].set_position(('axes', 1.1))  # 1.1向右便宜避免重叠
        ax3.set_ylabel('子图3-y轴名称')
        plt.plot(x, data3['lk_ra'], marker='*', color='purple', label='绘图三')
        plt.ylim(0, 0.12)
        # ax3.yaxis设置主刻度为： 倍数定位器、百分比格式器
        ax3.yaxis.set_major_locator(MultipleLocator(0.02))
        ax3.yaxis.set_major_formatter(ticker.PercentFormatter(xmax=1, decimals=0))
        plt.xticks(x, xx)
        ax3.legend(loc='upper right')

        plt.show()


class DemoLayout:

    @staticmethod
    def layout1_subplot_xyz():
        plt.figure()
        plt.subplot(221)
        plt.subplot(222)
        plt.subplot(212)
        plt.show()

    @staticmethod
    def layout2_add_subplot_gridspec():
        """
class GridSpec(GridSpecBase)
 |  GridSpec(nrows, ncols, figure=None, left=None, bottom=None, right=None, top=None, wspace=None, hspace=None, width_ratios=None, height_ratios=None)
 |
 |  A grid layout to place subplots within a figure.
 |
 |  The location of the grid cells is determined in a similar way to
 |  `~.figure.SubplotParams` using *left*, *right*, *top*, *bottom*, *wspace*
 |  and *hspace*.
 |
 |  Method resolution order:
 |      GridSpec
 |      GridSpecBase
 |      builtins.object
 |
 |  Methods defined here:
 |
 |  __getstate__(self)
 |
 |  __init__(self, nrows, ncols, figure=None, left=None, bottom=None, right=None, top=None, wspace=None, hspace=None, width_ratios=None, height_ratios=None)
 |      Parameters
 |      ----------
 |      nrows, ncols : int
 |          The number of rows and columns of the grid.
 |
 |      figure : `~.figure.Figure`, optional
 |          Only used for constrained layout to create a proper layoutbox.
 |
 |      left, right, top, bottom : float, optional
 |          Extent of the subplots as a fraction of figure width or height.
 |          Left cannot be larger than right, and bottom cannot be larger than
 |          top. If not given, the values will be inferred from a figure or
 |          rcParams at draw time. See also `GridSpec.get_subplot_params`.
 |
 |      wspace : float, optional
 |          The amount of width reserved for space between subplots,
 |          expressed as a fraction of the average axis width.
 |          If not given, the values will be inferred from a figure or
 |          rcParams when necessary. See also `GridSpec.get_subplot_params`.
 |
 |      hspace : float, optional
 |          The amount of height reserved for space between subplots,
 |          expressed as a fraction of the average axis height.
 |          If not given, the values will be inferred from a figure or
 |          rcParams when necessary. See also `GridSpec.get_subplot_params`.
 |
 |      width_ratios : array-like of length *ncols*, optional
 |          Defines the relative widths of the columns. Each column gets a
 |          relative width of ``width_ratios[i] / sum(width_ratios)``.
 |          If not given, all columns will have the same width.
 |
 |      height_ratios : array-like of length *nrows*, optional
 |          Defines the relative heights of the rows. Each column gets a
 |          relative height of ``height_ratios[i] / sum(height_ratios)``.
 |          If not given, all rows will have the same height.
 |
 |  get_subplot_params(self, figure=None)
 |      Return the `~.SubplotParams` for the GridSpec.
 |
 |      In order of precedence the values are taken from
 |
 |      - non-*None* attributes of the GridSpec
 |      - the provided *figure*
 |      - :rc:`figure.subplot.*`
 |
 |  locally_modified_subplot_params(self)
 |      Return a list of the names of the subplot parameters explicitly set
 |      in the GridSpec.
 |
 |      This is a subset of the attributes of `.SubplotParams`.
 |
 |  tight_layout(self, figure, renderer=None, pad=1.08, h_pad=None, w_pad=None, rect=None)
 |      Adjust subplot parameters to give specified padding.
 |
 |      Parameters
 |      ----------
 |      pad : float
 |          Padding between the figure edge and the edges of subplots, as a
 |          fraction of the font-size.
 |      h_pad, w_pad : float, optional
 |          Padding (height/width) between edges of adjacent subplots.
 |          Defaults to *pad*.
 |      rect : tuple of 4 floats, default: (0, 0, 1, 1), i.e. the whole figure
 |          (left, bottom, right, top) rectangle in normalized figure
 |          coordinates that the whole subplots area (including labels) will
 |          fit into.
 |
 |  update(self, **kwargs)
 |      Update the subplot parameters of the grid.
 |
 |      Parameters that are not explicitly given are not changed. Setting a
 |      parameter to *None* resets it to :rc:`figure.subplot.*`.
 |
 |      Parameters
 |      ----------
 |      left, right, top, bottom : float or None, optional
 |          Extent of the subplots as a fraction of figure width or height.
 |      wspace, hspace : float, optional
 |          Spacing between the subplots as a fraction of the average subplot
 |          width / height.
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from GridSpecBase:
 |
 |  __getitem__(self, key)
 |      Create and return a `.SubplotSpec` instance.
 |
 |  __repr__(self)
 |      Return repr(self).
 |
 |  get_geometry(self)
 |      Return a tuple containing the number of rows and columns in the grid.
 |
 |  get_grid_positions(self, fig, raw=False)
 |      Return the positions of the grid cells in figure coordinates.
 |
 |      Parameters
 |      ----------
 |      fig : `~matplotlib.figure.Figure`
 |          The figure the grid should be applied to. The subplot parameters
 |          (margins and spacing between subplots) are taken from *fig*.
 |      raw : bool, default: False
 |          If *True*, the subplot parameters of the figure are not taken
 |          into account. The grid spans the range [0, 1] in both directions
 |          without margins and there is no space between grid cells. This is
 |          used for constrained_layout.
 |
 |      Returns
 |      -------
 |      bottoms, tops, lefts, rights : array
 |          The bottom, top, left, right positions of the grid cells in
 |          figure coordinates.
 |
 |  get_height_ratios(self)
 |      Return the height ratios.
 |
 |      This is *None* if no height ratios have been set explicitly.
 |
 |  get_width_ratios(self)
 |      Return the width ratios.
 |
 |      This is *None* if no width ratios have been set explicitly.
 |
 |  new_subplotspec(self, loc, rowspan=1, colspan=1)
 |      Create and return a `.SubplotSpec` instance.
 |
 |      Parameters
 |      ----------
 |      loc : (int, int)
 |          The position of the subplot in the grid as
 |          ``(row_index, column_index)``.
 |      rowspan, colspan : int, default: 1
 |          The number of rows and columns the subplot should span in the grid.
 |
 |  set_height_ratios(self, height_ratios)
 |      Set the relative heights of the rows.
 |
 |      *height_ratios* must be of length *nrows*. Each row gets a relative
 |      height of ``height_ratios[i] / sum(height_ratios)``.
 |
 |  set_width_ratios(self, width_ratios)
 |      Set the relative widths of the columns.
 |
 |      *width_ratios* must be of length *ncols*. Each column gets a relative
 |      width of ``width_ratios[i] / sum(width_ratios)``.
 |
 |  subplots(self, *, sharex=False, sharey=False, squeeze=True, subplot_kw=None)
 |      Add all subplots specified by this `GridSpec` to its parent figure.
 |
 |      This utility wrapper makes it convenient to create common layouts of
 |      subplots in a single call.
 |
 |      Parameters
 |      ----------
 |      sharex, sharey : bool or {'none', 'all', 'row', 'col'}, default: False
 |          Controls sharing of properties among x (*sharex*) or y (*sharey*)
 |          axes:
 |
 |          - True or 'all': x- or y-axis will be shared among all subplots.
 |          - False or 'none': each subplot x- or y-axis will be independent.
 |          - 'row': each subplot row will share an x- or y-axis.
 |          - 'col': each subplot column will share an x- or y-axis.
 |
 |          When subplots have a shared x-axis along a column, only the x tick
 |          labels of the bottom subplot are created. Similarly, when subplots
 |          have a shared y-axis along a row, only the y tick labels of the
 |          first column subplot are created. To later turn other subplots'
 |          ticklabels on, use `~matplotlib.axes.Axes.tick_params`.
 |
 |      squeeze : bool, optional, default: True
 |          - If True, extra dimensions are squeezed out from the returned
 |            array of Axes:
 |
 |            - if only one subplot is constructed (nrows=ncols=1), the
 |              resulting single Axes object is returned as a scalar.
 |            - for Nx1 or 1xM subplots, the returned object is a 1D numpy
 |              object array of Axes objects.
 |            - for NxM, subplots with N>1 and M>1 are returned as a 2D array.
 |
 |          - If False, no squeezing at all is done: the returned Axes object
 |            is always a 2D array containing Axes instances, even if it ends
 |            up being 1x1.
 |
 |      subplot_kw : dict, optional
 |          Dict with keywords passed to the `~.Figure.add_subplot` call used
 |          to create each subplot.
 |
 |      Returns
 |      -------
 |      ax : `~.axes.Axes` object or array of Axes objects.
 |          *ax* can be either a single `~matplotlib.axes.Axes` object or
 |          an array of Axes objects if more than one subplot was created. The
 |          dimensions of the resulting array can be controlled with the
 |          squeeze keyword, see above.
 |
 |      See Also
 |      --------
 |      .pyplot.subplots
 |      .Figure.add_subplot
 |      .pyplot.subplot
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from GridSpecBase:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)
 |
 |  ncols
 |      The number of columns in the grid.
 |
 |  nrows
 |      The number of rows in the grid.

        """
        # use GridSpec
        # create figure
        fig1 = plt.figure(1) # constrained_layout=True)
        # create gridspec
        grid1 = plt.GridSpec(3, 3, figure=fig1)
        # add grid to subplot
        ax1 = fig1.add_subplot(grid1[0, 0:2])
        ax2 = fig1.add_subplot(grid1[1:3, 0])
        ax3 = fig1.add_subplot(grid1[0:3, 2])
        ax4 = fig1.add_subplot(grid1[1, 1])
        ax5 = fig1.add_subplot(grid1[2, 1])     # fail to set sharex=ax4
        plt.show()

    @staticmethod
    def layout3_add_gridspec():
        # use add_gridspec
        fig2 = plt.figure(num=2)    #, constrained_layout=True)
        grid2 = fig2.add_gridspec(3, 3)
        ax1 = fig2.add_subplot(grid2[0, 0:2])
        ax2 = fig2.add_subplot(grid2[1:3, 0])
        ax3 = fig2.add_subplot(grid2[0:3, 2])
        ax4 = fig2.add_subplot(grid2[1, 1])
        ax5 = fig2.add_subplot(grid2[2, 1])
        plt.show()

    @staticmethod
    def layout4_add_gridspec_constrained_tight(constrained=False, tight=False):
        fig3 = plt.figure(num=3, constrained_layout=constrained)
        grid3 = fig3.add_gridspec(3, 3)
        ax1 = fig3.add_subplot(grid3[0, 0:2])
        ax2 = fig3.add_subplot(grid3[1:3, 0])
        ax3 = fig3.add_subplot(grid3[0:3, 2])
        ax4 = fig3.add_subplot(grid3[1, 1])
        ax5 = fig3.add_subplot(grid3[2, 1])

        if tight:
            plt.tight_layout()
        if tight == 'pad10':
            plt.tight_layout(pad=1.5, h_pad=10, w_pad=10, rect=[0, 0, 1, 1])

        # fail to reset constrained_layout
        # plt.figure(3, constrained_layout=True)

    @staticmethod
    def layout5_subplot2grid(constrained=False, tight=False):
        # use constrained_layout to result in UserWarning, and faile to set!
        # use tight_layout is Ok!
        if constrained:
            # fig3, axs = plt.subplots(3, 3)
            fig3 = plt.figure(3, constrained_layout=True)
        else:
            fig3 = plt.figure(3)
        ax1 = plt.subplot2grid((3, 3), (0, 0))
        ax2 = plt.subplot2grid((3, 3), (0, 1), colspan=2)
        ax3 = plt.subplot2grid((3, 3), (1, 0), colspan=2, rowspan=2)
        ax4 = plt.subplot2grid((3, 3), (1, 2), rowspan=2)
        if tight:
            plt.tight_layout()

    @staticmethod
    def layout_sharexy_add_subplot_gridspec():
        # syntax sharex, sharey in add_subplot
        fig = plt.figure(constrained_layout=True)
        grid = plt.GridSpec(2, 2, figure=fig)
        ax1 = fig.add_subplot(grid[0, :], )
        ax2 = fig.add_subplot(grid[1, :], sharex=ax1)

    @staticmethod
    def layout_sharexy_subplots():
        # syntax sharex, sharey in subplots is Ok!
        fig, axs = plt.subplots(2, 2, sharex='col', facecolor='gray')
        axs[0, 0].plot(range(10), np.sin(range(10)), 'go-', markersize=10)
        axs[0, 1].plot(np.cos(range(10)), 'bo:', markersize=10)
        axs[1, 0].set(facecolor='purple')
        axs[1, 1].set(facecolor='yellow')

    @staticmethod
    def layout_adjust_tight_layout():
        fig = plt.figure()
        plt.subplot(221)
        plt.subplot(222)
        plt.subplot(212)
        plt.tight_layout(pad=0.2, h_pad=0.5, w_pad=0.2)    # rect=(0.1, 0.2, 0.9, 0.9)

    @staticmethod
    def layout_adjust_subplots_adjust():
        # 缺省设置
        plt.figure()
        plt.subplot(221)
        plt.subplot(222)
        plt.subplot(212)
        # plt.subplots_adjust(left=0.1, bottom=0.1, top=0.95, right=0.95, wspace=0.3, hspace=0.2)

        # 调整设置
        plt.figure()
        plt.subplot(221)
        plt.subplot(222)
        plt.subplot(212)
        plt.subplots_adjust(left=0.1, bottom=0.1, top=0.95, right=0.95)

        # 绘图区域居中调整（压缩了绘图区域的占有空间）
        plt.figure()
        plt.subplot(221)
        plt.subplot(222)
        plt.subplot(212)
        plt.subplots_adjust(left=0.3, bottom=0.3, top=0.70, right=0.70)

        # 增加子图之间的间隔
        plt.figure()
        plt.subplot(221)
        plt.subplot(222)
        plt.subplot(212)
        plt.subplots_adjust(left=0.3, bottom=0.3, top=0.70, right=0.70, wspace=0.35, hspace=0.35)


class DemoTick:

    @staticmethod
    def tick_ax_plt():
        """
        set ticks fromm sequence data
        plt mode: plt.x/yticks(ticks=tickarray, labels=labelarray)
        axe mode: ax.set_x/yticks(ticks=tickarray, labels=labelarray)
        """
        # 绘图数据
        xdata = np.arange(0, 2*np.pi, 0.1)
        ydata = np.sin(xdata)

        # 刻度及刻度标签
        xticks = [0, np.pi, 2*np.pi]
        yticks = [-1, -0.5, 0, 0.5, 1]
        xticklabels = ['0', r'$\pi$', r'$2\pi$']
        yticklabels = ['-1', r'-$\frac{1}{2}$', '0', r'-$\frac{1}{2}$', '1']

        # (1) 使用模块pyplot方法设置刻度及刻度标签
        # ax.x/yticks(ticks=tickarray)
        fig, ax1 = plt.subplots()
        ax1.set_xticks(ticks=xticks)
        ax1.set_yticks(ticks=yticks)
        ax1.plot(xdata, ydata)
        ax1.set_title("ax.set_x/yticks(ticks=x/yticks)")

        # (2) 使用子图方法设置刻度及刻度标签
        # ax.x/yticks(ticks=tickarray), ax.set_x/ylabels(labels=labelarray)
        fig, ax2 = plt.subplots()
        ax2.set(xticks=xticks, yticks=yticks,
                xticklabels=xticklabels, yticklabels=yticklabels,
                title="ax.set_x/yticks(ticks=x/yticks)\n"
                      "ax.set_x/yticklabels(labels=x/ylabels)"
                )
        ax2.plot(xdata, ydata)

        # (3) 使用模块pyplot方法设置刻度及刻度标签
        # plt.x/yticks(ticks=tickarray, labels=labelarray)
        plt.figure(3)
        # plt.subplot()
        plt.xticks(ticks=xticks, labels=xticklabels)
        plt.yticks(ticks=yticks, labels=yticklabels)
        plt.plot(xdata, ydata)
        plt.title("plt.x/yticks(ticks=x/yticks, "
                  "\n      labels=x/yticklabels)")

    @staticmethod
    def tick_major_minor():
        """
        set ticks from sequence data
        Axes mode
        """
        # 创建画板和子图
        fig = plt.figure()
        ax = fig.add_subplot()

        # 绘制正弦曲线
        xdata = np.arange(0, 2 * np.pi + 0.1, 0.1)
        ydata = np.sin(xdata)
        ax.plot(xdata, ydata)

        # 刻度设置数据
        xticks = [0, np.pi/2, np.pi, np.pi*3/2, 2*np.pi]
        xticklabels = ['0', r'$\pi/2$', r'$\pi$', r'$3/2\pi$', r'$2\pi$']
        yticks_major = [-1, 0, 1]
        yticks_minor = [-1, -0.75, -0.5, -0.25, 0, 0.25, 0.5, 0.75, 1]

        # 设置X轴刻度和刻度标签
        ax.set_xticks(xticks)
        ax.set_xticklabels(labels=xticklabels, fontsize=10)
        # 设置Y轴主刻度和副刻度，副刻度标签字体为8号，颜色为蓝色，旋转30度
        ax.set_yticks(ticks=yticks_major)
        ax.set_yticks(ticks=yticks_minor, minor=True)
        ax.set_yticklabels(labels=yticks_minor, minor=True, fontsize=8, color='b', rotation=30)

        # 显示x轴主刻度网格线，y轴副刻度网格线
        ax.xaxis.grid(True, which='major')
        ax.yaxis.grid(True, which='minor')

        # ax.tick_params(axis='y', which='minor', labelleft=True)
        # ax.tick_params(axis='y', which='major', length=10)
        # ax.tick_params(axis='y', which='minor', length=5)


        # use MarkDown Text to display special char and formulas
        # yticklabels = ['-1', r'-$\frac{1}{2}$ medium ', '0', r'-$\frac{1}{2}$', '1']
        # fontdictx = {'fontsize': 16,
        #              'fontstyle': 'italic' if itlic else 'normal',
        #              'fontweight': 'bold',
        #              'verticalalignment': 'center',
        #              'horizontalalignment': 'center'
        #              }
        # fontdicty = {'fontsize': 16,
        #              'fontstyle': 'italic' if itlic else 'normal',
        #              'fontweight': 'bold',
        #              'verticalalignment': 'center',
        #              'horizontalalignment': 'right'  #'center'
        #              }
        # ax.set_xticklabels(labels=xticklabels, fontdict=fontdictx)
        # ax.set_yticklabels(yticklabels, fontdict=fontdicty)

    @staticmethod
    def ticklabels_alignment():
        xticks = [0, np.pi, 2*np.pi]
        yticks = [-1, -0.5, 0, 0.5, 1]

        xticklabels = ['0', r'$\pi$', r'$2\pi$']
        yticklabels = ['y=-1', r'y=-$\frac{1}{2}$', 'y=0', r'y=-$\frac{1}{2}$', '1']
        # yticklabels = ['bottom', '$-\frac{1}{2}$', 'mid', 'big', 'top']

        fontdictx = {'fontsize': 14,
                    'fontstyle': 'normal',
                    'fontweight': 'normal',
                    'verticalalignment': 'center',
                    'horizontalalignment': 'center'
                    }
        fontdicty = {'fontsize': 14,
                    'fontstyle': 'normal',
                    'fontweight': 'normal',
                    'verticalalignment': 'center',
                    'horizontalalignment': 'right'
                    }

        xdata = np.arange(0, 2*np.pi, 0.4)
        ydata = np.sin(np.arange(0, 2*np.pi, 0.4))

        horizon = ['center', 'top', 'bottom', 'baseline']
        vertical = ['left', 'right', 'center']

        fig, axs = plt.subplots(4, 3)
        for i in range(4):
            for j in range(3):
                fontdictx['verticalalignment'] = horizon[i]
                fontdictx['horizontalalignment'] = vertical[j]
                axs[i, j].set_xticks(xticks)
                axs[i, j].set_xticklabels(labels=xticklabels, fontdict=fontdictx)
                axs[i, j].plot(xdata, ydata)

        fig, axs = plt.subplots(4, 3)
        for i in range(4):
            for j in range(3):
                fontdicty['verticalalignment'] = horizon[i]
                fontdicty['horizontalalignment'] = vertical[j]
                axs[i, j].set_yticks(yticks)
                axs[i, j].set_yticklabels(yticklabels, fontdict=fontdicty)
                axs[i, j].plot(xdata, ydata)

    @staticmethod
    def ticklabels_markdown():
        """
        set_xticks(self, ticks, *, minor=False)
            Set the xaxis' tick locations.

            Parameters
            ----------
            ticks : list of floats
                List of tick locations.
            minor : bool, default: False
                If ``False``, set the major ticks; if ``True``, the minor ticks.
        """
        # set_ticks, LaTex in label
        fig, ax = plt.subplots()
        ax.set_xticks([0, np.pi / 2, np.pi, 3 * np.pi / 2, 2 * np.pi])
        ax.set_yticks([-1, 0, 1])
        ax.set_xticklabels(['0', r'$\frac{\pi}{2}$', r'$\pi$', r'$\frac{3\pi}{2}$', r'$2\pi$'])
        ax.set_yticklabels(['-1', '0', '1'])

        ax.tick_params(axis='x',
                       labelsize=15,
                       rotation=90,
                       )

        ax.plot(np.arange(0, 2*np.pi, 0.5),
                [np.sin(x) for x in np.arange(0, 2*np.pi, 0.5)])

        ax.set_xlabel(xlabel=r'$y = sqrt(x)$',
                      fontdict={'color':'green', 'fontsize': 15},
                      labelcolor='red')
        ax.set_ylabel(ylabel='function value',
                      rotation=90)

        ax.set(color='red')

        # plt.xticks(visible=False)       # can not be used in set_xyticks, tick_params
        plt.show()

    @staticmethod
    def tick_params():
        """
tick_params(axis='both', **kwargs)
    Change the appearance of ticks, tick labels, and gridlines.

    Tick properties that are not explicitly set using the keyword
    arguments remain unchanged unless *reset* is True.

    Parameters
    ----------
    axis : {'x', 'y', 'both'}, default: 'both'
        The axis to which the parameters are applied.
    which : {'major', 'minor', 'both'}, default: 'major'
        The group of ticks to which the parameters are applied.
    reset : bool, default: False
        Whether to reset the ticks to defaults before updating them.

    Other Parameters
    ----------------
    direction : {'in', 'out', 'inout'}
        Puts ticks inside the axes, outside the axes, or both.
    length : float
        Tick length in points.
    width : float
        Tick width in points.
    color : color
        Tick color.
    pad : float
        Distance in points between tick and label.
    labelsize : float or str
        Tick label font size in points or as a string (e.g., 'large').
    labelcolor : color
        Tick label color.
    colors : color
        Tick color and label color.
    zorder : float
        Tick and label zorder.
    bottom, top, left, right : bool
        Whether to draw the respective ticks.
    labelbottom, labeltop, labelleft, labelright : bool
        Whether to draw the respective tick labels.
    labelrotation : float
        Tick label rotation
    grid_color : color
        Gridline color.
    grid_alpha : float
        Transparency of gridlines: 0 (transparent) to 1 (opaque).
    grid_linewidth : float
        Width of gridlines in points.
    grid_linestyle : str
        Any valid `.Line2D` line style spec.

    Examples
    --------
    ::

        ax.tick_params(direction='out', length=6, width=2, colors='r',
                       grid_color='r', grid_alpha=0.5)

    This will make all major ticks be red, pointing out of the box,
    and with dimensions 6 points by 2 points.  Tick labels will
    also be red.  Gridlines will be red and translucent.
        """
        fig, ax = plt.subplots(1, 3, figsize=(12, 4))
        fig.subplots_adjust(top=0.9, bottom=0.1, wspace=0.2)
        ax[0].tick_params(
            axis='both',
            direction='out',
            length=5,
            width=3,
            labelrotation=90,
            labelsize=10,
            grid_color='r',
            )
        ax[1].xaxis.grid(True)
        ax[1].yaxis.grid(True)
        ax[1].tick_params(
            axis='x',
            direction='in',
            length=5,
            width=3,
            color='blue',
            labelrotation=30,
            labelsize=10,
            labelbottom=False,
            labeltop=True,
            grid_color='r',
            grid_linestyle=':',
            )
        ax[2].tick_params(
            axis='y',
            direction='in',
            length=5,
            width=3,
            color='r',
            right=True,
            labelrotation=-30,
            labelsize=10,
            labelcolor='g',
            labelright=True
            )

    @staticmethod
    def ticklabel_format_offset_mathtext():
        """
ticklabel_format(self, *, axis='both', style='', scilimits=None, useOffset=None, useLocale=None, useMathText=None)
    Configure the `.ScalarFormatter` used by default for linear axes.

    If a parameter is not set, the corresponding property of the formatter
    is left unchanged.

    Parameters
    ----------
    axis : {'x', 'y', 'both'}, default: 'both'
        The axes to configure.  Only major ticks are affected.

    style : {'sci', 'scientific', 'plain'}
        Whether to use scientific notation.
        The formatter default is to use scientific notation.

    scilimits : pair of ints (m, n)
        Scientific notation is used only for numbers outside the range
        10\ :sup:`m` to 10\ :sup:`n` (and only if the formatter is
        configured to use scientific notation at all).  Use (0, 0) to
        include all numbers.  Use (m, m) where m != 0 to fix the order of
        magnitude to 10\ :sup:`m`.
        The formatter default is :rc:`axes.formatter.limits`.

    useOffset : bool or float
        If True, the offset is calculated as needed.
        If False, no offset is used.
        If a numeric value, it sets the offset.
        The formatter default is :rc:`axes.formatter.useoffset`.

    useLocale : bool
        Whether to format the number using the current locale or using the
        C (English) locale.  This affects e.g. the decimal separator.  The
        formatter default is :rc:`axes.formatter.use_locale`.

    useMathText : bool
        Render the offset and scientific notation in mathtext.
        The formatter default is :rc:`axes.formatter.use_mathtext`.

    Raises
    ------
    AttributeError
        If the current formatter is not a `.ScalarFormatter`.
        """
        fig, [[ax1, ax2], [ax3, ax4], [ax5, ax6], [ax7, ax8]] = plt.subplots(4, 2, figsize=(6, 8))

        x = np.arange(0, 1, .01)

        # useMathText: [0, 1e5+1e10], [0, 1e-10+1e-5]
        # useOffset=False
        ax1.plot(x * 1e3 + 1e10, x * 1e-10 + 1e-5)
        ax1.ticklabel_format(useOffset=False)
        # useOffset=True
        ax2.plot(x * 1e3 + 1e10, x * 1e-10 + 1e-5)
        ax2.ticklabel_format(useOffset=True)

        # [0, 1e5], [0, 1e-4]
        # useOffset=False
        ax3.plot(x * 1e5, x * 1e-4)
        ax3.ticklabel_format(useOffset=False)
        # useMathText=True
        ax4.plot(x * 1e5, x * 1e-4)
        ax4.ticklabel_format(useOffset=True)

        # [-1e5-1e10, -1e10], [-1e-5-1e-10, -1e-10]
        # useMathText=False
        ax5.plot(-x * 1e5 - 1e10, -x * 1e-5 - 1e-10)
        ax5.ticklabel_format(useMathText=False)
        # useMathText=True
        ax6.plot(-x * 1e5 - 1e10, -x * 1e-5 - 1e-10)
        ax6.ticklabel_format(useMathText=True)

        # [-1e5, 0], [-1e-4, 0]
        # useMathText=False
        ax7.plot(-x * 1e5, -x * 1e-4)
        ax7.ticklabel_format(useMathText=False)
        # useMathText=True
        ax8.plot(-x * 1e5, -x * 1e-4)
        ax8.ticklabel_format(useMathText=True)

        fig.subplots_adjust(wspace=0.4, hspace=0.5)
        fig.text(0.5, 0.975, 'useMathText, useOffset',
                 horizontalalignment='center',
                 verticalalignment='top')

    @staticmethod
    def ticklabel_format_offset():
        """
        使用刻度偏移量
        显示最基本的变化值
        """
        fig, [ax1, ax2] = plt.subplots(1, 2, figsize=(12, 6))

        # X:[0, 1e3+1e10], Y:[0, 1e-10+1e-3]
        x = np.arange(0, 1, .01)
        datax = x * 1e3 + 1e10
        datay = x * 1e-10 + 1e-3

        # 未使用偏移量，显示变化不清晰
        ax1.plot(datax, datay)
        ax1.ticklabel_format(useOffset=False)
        ax1.set_xlabel('useOffset=False')

        # 使用偏移量，去除基础量，突出变化量
        ax2.plot(datax, datay)
        ax2.ticklabel_format(useOffset=True)
        ax2.set_xlabel('useOffset=True')

    @staticmethod
    def ticks_position():
        fig, axs = plt.subplots(1, 4, figsize=(12, 3))
        fig.subplots_adjust(hspace=0.3)

        axs[0].xaxis.set_ticks_position('top')
        axs[0].text(0.1, 0.5, 'xtick on top', fontsize=16)

        axs[1].xaxis.set_ticks_position('both')
        axs[1].text(0.1, 0.5, 'xtick on both', fontsize=16)

        axs[2].xaxis.set_ticks_position('none')
        axs[2].text(0.1, 0.5, 'xtick on none', fontsize=16)

        axs[3].yaxis.set_ticks_position('right')
        axs[3].text(0.1, 0.5, 'ytick on right', fontsize=16)

    @staticmethod
    def tick_off():
        fig, ax = plt.subplots()
        ax.yaxis.set_major_locator(plt.NullLocator())
        ax.xaxis.set_major_formatter(plt.NullFormatter())

    @staticmethod
    def tick_grid():
        fig, ax = plt.subplots()
        ax.xaxis.grid(True, which='major')      # 打开x坐标轴主刻度的网格
        ax.yaxis.grid(True, which='major')      # 打开y坐标轴次刻度的网格

        # need to set minor ticker
        ax.xaxis.grid(True, which='minor')      # 打开x坐标轴主刻度的网格
        ax.yaxis.grid(True, which='minor')      # 打开y坐标轴次刻度的网格


class DemoLocatorFormatter:

    @staticmethod
    def multiplelocator_strformatter():
        # 导入定位器和格式器
        from matplotlib.ticker import MultipleLocator, FormatStrFormatter

        # 创建画板和子图
        fig, ax = plt.subplots(figsize=(12, 4))

        # 绘制数据
        x = np.arange(0.0, np.pi*4, 0.1)
        y = np.sin(x)
        plt.plot(x, y, 'r')

        # 使用定位器、格式器设置主刻度
        xmajorLocator = MultipleLocator(2*np.pi/4)          # 将x主刻度标签设置为2pi的倍数
        xmajorFormatter = FormatStrFormatter('%1.2f')       # 设置x轴标签文本的格式
        ymajorLocator = MultipleLocator(0.25)               # 将y轴主刻度标签设置为0.5的倍数
        ymajorFormatter = FormatStrFormatter('%1.2f')       # 设置y轴标签文本的格式
        # 配置定位器、格式器
        ax.xaxis.set_major_locator(xmajorLocator)
        ax.xaxis.set_major_formatter(xmajorFormatter)
        ax.yaxis.set_major_locator(ymajorLocator)
        ax.yaxis.set_major_formatter(ymajorFormatter)
        # 设置xaxis标签, 设置标签后将会覆盖格式器标签
        # xlabels = [f'{(j-1)*2}'+r'$\pi$' for j in range(18)]
        # ax.set_xticklabels(xlabels)

        # 使用定位器设置次刻度
        xminorLocator = MultipleLocator(2*np.pi/20)          # 将x轴次刻度标签设置为1/10pi的倍数
        yminorLocator = MultipleLocator(0.05)                # 将此y轴次刻度标签设置为0.05的倍数
        # 配置次刻度标签定位器,没有标签文本格式
        ax.xaxis.set_minor_locator(xminorLocator)
        ax.yaxis.set_minor_locator(yminorLocator)

        ax.xaxis.grid(True, which='major')      # 打开x坐标轴主刻度的网格
        ax.yaxis.grid(True, which='major')      # 打开y坐标轴主、副刻度的网格
        ax.yaxis.grid(True, which='minor')

    @staticmethod
    def nulllocator_or_nullformatter():
        # 创建子图
        ax = plt.axes()

        # 绘制有关数据点
        x = np.random.rand(50)
        y = np.random.rand(50)
        cs = [np.random.randint(1, 100) for _ in range(50)]
        ax.scatter(x, y, c=cs, s=cs)

        # 设置x轴格式器为空格式器，不显示刻度标签
        ax.xaxis.set_major_formatter(plt.NullFormatter())
        # 设置y轴定位器为空定位器，不显示刻度和刻度标签
        ax.yaxis.set_major_locator(plt.NullLocator())
        # 设置x轴刻度的有关特性
        ax.tick_params(axis='x', which='major', direction='in',
                       length=5, width=5, top=True, bottom=True)

    @staticmethod
    def nulllocator_and_nullformatter():
        """set axis invisible by using NullLocator"""
        fig, ax = plt.subplots(5, 5, figsize=(5, 5))
        fig.subplots_adjust(hspace=0, wspace=0)

        # Get some face data from scikit-learn
        # maybe need to wait a few seconds
        from sklearn.datasets import fetch_olivetti_faces
        faces = fetch_olivetti_faces().images

        for i in range(5):
            for j in range(5):
                ax[i, j].xaxis.set_major_locator(plt.NullLocator())
                ax[i, j].yaxis.set_major_locator(plt.NullLocator())
                ax[i, j].imshow(faces[10 * i + j], cmap="bone")

    @staticmethod
    def maxnlocator():
        # 创建画板和子图
        fig, axi = plt.subplots()
        # 使用最大值定位器设置x轴主副刻度
        axi.xaxis.set_major_locator(plt.MaxNLocator(5))
        axi.xaxis.set_minor_locator(plt.MaxNLocator(25))
        # 使用最大定位器设置y轴主副刻度，并显示刻度线
        axi.yaxis.set_major_locator(plt.MaxNLocator(4))
        axi.yaxis.set_minor_locator(plt.MaxNLocator(20))
        axi.yaxis.grid('y', 'major', linewidth=3)
        axi.yaxis.grid('y', 'minor', linestyle=':', linewidth=1)

    @staticmethod
    def funcformatter():
        fig, ax = plt.subplots()
        x = np.arange(0, 2*np.pi+0.1, 0.1)
        ax.plot(x, np.sin(x))
        ax.set_xticks([np.pi/2*j for j in range(5)])

        def format_func(value, pos):
            _v = int(2*value/np.pi + 1e-10)
            if _v == 0:
                return "0"
            elif _v == 1:
                return r"$\pi/2$"
            elif _v == 2:
                return r"$\pi$"
            elif _v % 2 > 0:
                return r"${0}/2\pi$".format(_v)
            else:
                return r"${0}\pi$".format(_v // 2)

        ax.xaxis.set_major_formatter(plt.FuncFormatter(format_func))
        ax.xaxis.grid('x', 'major')


class DemoPlot:

    @staticmethod
    def test_plot():
        x = np.arange(0, 2*np.pi, 0.1)
        y = np.sin(x)

        fig1, ax1 = plt.subplots()
        ax1.plot(x, y, 'go--')

        fig2, ax2 = plt.subplots()
        ax2.plot(x, y, 'ch:')

        fig3, ax3 = plt.subplots()
        ax3.plot(x, y, color='g', linestyle='--', marker='h', linewidth=2, markersize=5)

        data = dict(x=x, y=y)
        fig4, ax4 = plt.subplots()
        ax4.plot('x', 'y', data=data, linestyle=(3, (2, 3, 5, 1)))

        # ax.set(facecolor='yellow')


class DemoScatter:

    """
scatter(x, y, s=None, c=None, marker=None, cmap=None, norm=None, vmin=None, vmax=None, alpha=None,
        linewidths=None, verts=<deprecated parameter>, edgecolors=None, *, plotnonfinite=False,
        data=None, **kwargs)
    A scatter plot of *y* vs. *x* with varying marker size and/or color.

    Parameters
    ----------
    x, y : float or array-like, shape (n, )
        The data positions.

    s : float or array-like, shape (n, ), optional
        The marker size in points**2.
        Default is ``rcParams['lines.markersize'] ** 2``.

    c : array-like or list of colors or color, optional
        The marker colors. Possible values:

        - A scalar or sequence of n numbers to be mapped to colors using
          *cmap* and *norm*.
        - A 2-D array in which the rows are RGB or RGBA.
        - A sequence of colors of length n.
        - A single color format string.

        Note that *c* should not be a single numeric RGB or RGBA sequence
        because that is indistinguishable from an array of values to be
        colormapped. If you want to specify the same RGB or RGBA value for
        all points, use a 2-D array with a single row.  Otherwise, value-
        matching will have precedence in case of a size matching with *x*
        and *y*.

        If you wish to specify a single color for all points
        prefer the *color* keyword argument.

        Defaults to `None`. In that case the marker color is determined
        by the value of *color*, *facecolor* or *facecolors*. In case
        those are not specified or `None`, the marker color is determined
        by the next color of the ``Axes``' current "shape and fill" color
        cycle. This cycle defaults to :rc:`axes.prop_cycle`.

    marker : `~.markers.MarkerStyle`, default: :rc:`scatter.marker`
        The marker style. *marker* can be either an instance of the class
        or the text shorthand for a particular marker.
        See :mod:`matplotlib.markers` for more information about marker
        styles.

    cmap : str or `~matplotlib.colors.Colormap`, default: :rc:`image.cmap`
        A `.Colormap` instance or registered colormap name. *cmap* is only
        used if *c* is an array of floats.

    norm : `~matplotlib.colors.Normalize`, default: None
        If *c* is an array of floats, *norm* is used to scale the color
        data, *c*, in the range 0 to 1, in order to map into the colormap
        *cmap*.
        If *None*, use the default `.colors.Normalize`.

    vmin, vmax : float, default: None
        *vmin* and *vmax* are used in conjunction with the default norm to
        map the color array *c* to the colormap *cmap*. If None, the
        respective min and max of the color array is used.
        It is deprecated to use *vmin*/*vmax* when *norm* is given.

    alpha : float, default: None
        The alpha blending value, between 0 (transparent) and 1 (opaque).

    linewidths : float or array-like, default: :rc:`lines.linewidth`
        The linewidth of the marker edges. Note: The default *edgecolors*
        is 'face'. You may want to change this as well.

    edgecolors : {'face', 'none', *None*} or color or sequence of color, default: :rc:`scatter.edgecolors`
        The edge color of the marker. Possible values:

        - 'face': The edge color will always be the same as the face color.
        - 'none': No patch boundary will be drawn.
        - A color or sequence of colors.

        For non-filled markers, the *edgecolors* kwarg is ignored and
        forced to 'face' internally.

    plotnonfinite : bool, default: False
        Set to plot points with nonfinite *c*, in conjunction with
        `~matplotlib.colors.Colormap.set_bad`.

    Returns
    -------
    `~matplotlib.collections.PathCollection`

    Other Parameters
    ----------------
    **kwargs : `~matplotlib.collections.Collection` properties

    See Also
    --------
    plot : To plot scatter plots when markers are identical in size and
        color.

    Notes
    -----
    * The `.plot` function will be faster for scatterplots where markers
      don't vary in size or color.

    * Any or all of *x*, *y*, *s*, and *c* may be masked arrays, in which
      case all masks will be combined and only unmasked points will be
      plotted.

    * Fundamentally, scatter works with 1-D arrays; *x*, *y*, *s*, and *c*
      may be input as N-D arrays, but within scatter they will be
      flattened. The exception is *c*, which will be flattened only if its
      size matches the size of *x* and *y*.

    .. note::
        In addition to the above described arguments, this function can take
        a *data* keyword argument. If such a *data* argument is given,
        the following arguments can also be string ``s``, which is
        interpreted as ``data[s]`` (unless this raises an exception):
        *x*, *y*, *s*, *linewidths*, *edgecolors*, *c*, *facecolor*, *facecolors*, *color*.

        Objects passed as **data** must support item access (``data[s]``) and
        membership syntax (``s in data``).
    """

    def __init__(self):
        self.x = np.arange(0, 10, 0.5)
        self.y = np.sin(self.x)

    @staticmethod
    def scatter_sin():
        import random
        x = np.arange(0, 2*np.pi, 0.1)
        y = np.sin(x)
        z = np.cos(x)
        cset = ['red', 'blue', 'yellow', 'gray', 'purple']
        sset = list(range(10, 500))

        fig, ax = plt.subplots(figsize=(12, 5))

        ax.scatter(x, y,
                   s=[random.sample(sset, 1)[0] for _ in y],
                   c=[random.sample(cset, 1)[0] for _ in y],
                   alpha=0.5,
                   marker='h'
                   )

    @staticmethod
    def scatter_random():
        x = np.arange(0, 10, 0.2)
        y = np.random.randint(-3, 4, size=len(x))

        fig, ax = plt.subplots(figsize=(12, 5))
        ax.scatter(x, y,
                   c=np.random.randint(50, 230, size=len(x)),
                   s=np.random.randint(10, 1000, size=len(x)),
                   alpha=0.5,
                   marker='o',
                   edgecolors='blue',
                   linewidths=3
                   )
        ax.set(xlim=[-0.5, 10.5], ylim=[-3.5, 3.5])

    @staticmethod
    def set_marker():
        x = np.arange(0, 10, 0.5)
        y = np.sin(x)
        fig = plt.figure()
        ax1 = fig.add_subplot(211)
        ax2 = fig.add_subplot(212)
        ax1.scatter(x, y,
                    s=[np.random.randint(300, 1000) for _ in range(len(x))],
                    marker='o', color='gray', edgecolors='g', linewidths=2,
                    alpha=0.8)
        ax2.scatter(x, np.cos(x),
                    s=[np.random.randint(100,3000) for _ in range(len(x))],
                    c=[np.random.randint(3,250) for _ in range(len(x))],
                    marker='o',
                    alpha=0.7)


class DemoBar:
    """
    bar(x, height, width=0.8, bottom=None, *, align='center', data=None, **kwargs)
        Make a bar plot.

        The bars are positioned at *x* with the given *align*\ment. Their
        dimensions are given by *height* and *width*. The vertical baseline
        is *bottom* (default 0).

        Many parameters can take either a single value applying to all bars
        or a sequence of values, one for each bar.

        Parameters
        ----------
        x : float or array-like
            The x coordinates of the bars. See also *align* for the
            alignment of the bars to the coordinates.

        height : float or array-like
            The height(s) of the bars.

        width : float or array-like, default: 0.8
            The width(s) of the bars.

        bottom : float or array-like, default: 0
            The y coordinate(s) of the bars bases.

        align : {'center', 'edge'}, default: 'center'
            Alignment of the bars to the *x* coordinates:

            - 'center': Center the base on the *x* positions.
            - 'edge': Align the left edges of the bars with the *x* positions.

            To align the bars on the right edge pass a negative *width* and
            ``align='edge'``.

        Returns
        -------
        `.BarContainer`
            Container with all the bars and optionally errorbars.

        Other Parameters
        ----------------
        color : color or list of color, optional
            The colors of the bar faces.

        edgecolor : color or list of color, optional
            The colors of the bar edges.

        linewidth : float or array-like, optional
            Width of the bar edge(s). If 0, don't draw edges.

        tick_label : str or list of str, optional
            The tick labels of the bars.
            Default: None (Use default numeric labels.)

        xerr, yerr : float or array-like of shape(N,) or shape(2, N), optional
            If not *None*, add horizontal / vertical errorbars to the bar tips.
            The values are +/- sizes relative to the data:

            - scalar: symmetric +/- values for all bars
            - shape(N,): symmetric +/- values for each bar
            - shape(2, N): Separate - and + values for each bar. First row
              contains the lower errors, the second row contains the upper
              errors.
            - *None*: No errorbar. (Default)

            See :doc:`/gallery/statistics/errorbar_features`
            for an example on the usage of ``xerr`` and ``yerr``.

        ecolor : color or list of color, default: 'black'
            The line color of the errorbars.

        capsize : float, default: :rc:`errorbar.capsize`
           The length of the error bar caps in points.

        error_kw : dict, optional
            Dictionary of kwargs to be passed to the `~.Axes.errorbar`
            method. Values of *ecolor* or *capsize* defined here take
            precedence over the independent kwargs.

        log : bool, default: False
            If *True*, set the y-axis to be log scale.

        **kwargs : `.Rectangle` properties

        Properties:
            agg_filter: a filter function, which takes a (m, n, 3) float array and a dpi value, and returns a (m, n, 3) array
            alpha: float or None
            animated: bool
            antialiased or aa: unknown
            capstyle: {'butt', 'round', 'projecting'}
            clip_box: `.Bbox`
            clip_on: bool
            clip_path: Patch or (Path, Transform) or None
            color: color
            contains: unknown
            edgecolor or ec: color or None or 'auto'
            facecolor or fc: color or None
            figure: `.Figure`
            fill: bool
            gid: str
            hatch: {'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
            in_layout: bool
            joinstyle: {'miter', 'round', 'bevel'}
            label: object
            linestyle or ls: {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
            linewidth or lw: float or None
            path_effects: `.AbstractPathEffect`
            picker: None or bool or callable
            rasterized: bool or None
            sketch_params: (scale: float, length: float, randomness: float)
            snap: bool or None
            transform: `.Transform`
            url: str
            visible: bool
            zorder: float

        See Also
        --------
        barh: Plot a horizontal bar plot.

        Notes
        -----
        Stacked bars can be achieved by passing individual *bottom* values per
        bar. See :doc:`/gallery/lines_bars_and_markers/bar_stacked`.

        .. note::
            In addition to the above described arguments, this function can take
            a *data* keyword argument. If such a *data* argument is given,
            every other argument can also be string ``s``, which is
            interpreted as ``data[s]`` (unless this raises an exception).

            Objects passed as **data** must support item access (``data[s]``) and
            membership syntax (``s in data``).
    """

    # barh
    """
    barh(y, width, height=0.8, left=None, *, align='center', **kwargs)
        Make a horizontal bar plot.
        
        The bars are positioned at *y* with the given *align*\ment. Their
        dimensions are given by *width* and *height*. The horizontal baseline
        is *left* (default 0).
        
        Many parameters can take either a single value applying to all bars
        or a sequence of values, one for each bar.
        
        Parameters
        ----------
        y : float or array-like
            The y coordinates of the bars. See also *align* for the
            alignment of the bars to the coordinates.
        
        width : float or array-like
            The width(s) of the bars.
        
        height : float or array-like, default: 0.8
            The heights of the bars.
        
        left : float or array-like, default: 0
            The x coordinates of the left sides of the bars.
        
        align : {'center', 'edge'}, default: 'center'
            Alignment of the base to the *y* coordinates*:
        
            - 'center': Center the bars on the *y* positions.
            - 'edge': Align the bottom edges of the bars with the *y*
              positions.
        
            To align the bars on the top edge pass a negative *height* and
            ``align='edge'``.
        
        Returns
        -------
        `.BarContainer`
            Container with all the bars and optionally errorbars.
        
        Other Parameters
        ----------------
        color : color or list of color, optional
            The colors of the bar faces.
        
        edgecolor : color or list of color, optional
            The colors of the bar edges.
        
        linewidth : float or array-like, optional
            Width of the bar edge(s). If 0, don't draw edges.
        
        tick_label : str or list of str, optional
            The tick labels of the bars.
            Default: None (Use default numeric labels.)
        
        xerr, yerr : float or array-like of shape(N,) or shape(2, N), optional
            If not ``None``, add horizontal / vertical errorbars to the
            bar tips. The values are +/- sizes relative to the data:
        
            - scalar: symmetric +/- values for all bars
            - shape(N,): symmetric +/- values for each bar
            - shape(2, N): Separate - and + values for each bar. First row
              contains the lower errors, the second row contains the upper
              errors.
            - *None*: No errorbar. (default)
        
            See :doc:`/gallery/statistics/errorbar_features`
            for an example on the usage of ``xerr`` and ``yerr``.
        
        ecolor : color or list of color, default: 'black'
            The line color of the errorbars.
        
        capsize : float, default: :rc:`errorbar.capsize`
           The length of the error bar caps in points.
        
        error_kw : dict, optional
            Dictionary of kwargs to be passed to the `~.Axes.errorbar`
            method. Values of *ecolor* or *capsize* defined here take
            precedence over the independent kwargs.
        
        log : bool, default: False
            If ``True``, set the x-axis to be log scale.
        
        **kwargs : `.Rectangle` properties
        
        Properties:
            agg_filter: a filter function, which takes a (m, n, 3) float array and a dpi value, and returns a (m, n, 3) array
            alpha: float or None
            animated: bool
            antialiased or aa: unknown
            capstyle: {'butt', 'round', 'projecting'}
            clip_box: `.Bbox`
            clip_on: bool
            clip_path: Patch or (Path, Transform) or None
            color: color
            contains: unknown
            edgecolor or ec: color or None or 'auto'
            facecolor or fc: color or None
            figure: `.Figure`
            fill: bool
            gid: str
            hatch: {'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
            in_layout: bool
            joinstyle: {'miter', 'round', 'bevel'}
            label: object
            linestyle or ls: {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
            linewidth or lw: float or None
            path_effects: `.AbstractPathEffect`
            picker: None or bool or callable
            rasterized: bool or None
            sketch_params: (scale: float, length: float, randomness: float)
            snap: bool or None
            transform: `.Transform`
            url: str
            visible: bool
            zorder: float
        
        See Also
        --------
        bar: Plot a vertical bar plot.
        
        Notes
        -----
        Stacked bars can be achieved by passing individual *left* values per
        bar. See
        :doc:`/gallery/lines_bars_and_markers/horizontal_barchart_distribution`
        .
    """

    @staticmethod
    def bar_default():
        x = range(10)
        height = np.random.randint(1, 20, size=10)

        fig, ax = plt.subplots()
        ax.bar(x, height)

    @staticmethod
    def bar_width():
        x = range(10)
        height = np.random.randint(10, 20, size=10)
        fig, ax = plt.subplots()
        ax.bar(x, height, width=0.3, align='edge')

    @staticmethod
    def bar_color():
        x = range(10)
        height = np.random.randint(10, 20, size=10)
        color = np.random.randint(200, 250, size=10)

        fig, ax = plt.subplots()
        ax.bar(x, height, width=0.3, color=color)


class DemoPie:

    """
    pie(x, explode=None, labels=None, colors=None, autopct=None, pctdistance=0.6, shadow=False, labeldistance=1.1,
        startangle=0, radius=1, counterclock=True, wedgeprops=None, textprops=None, center=(0, 0), frame=False,
        rotatelabels=False, *, normalize=None, data=None)

        Plot a pie chart.

        Make a pie chart of array *x*.  The fractional area of each wedge is
        given by ``x/sum(x)``.  If ``sum(x) < 1``, then the values of *x* give
        the fractional area directly and the array will not be normalized. The
        resulting pie will have an empty wedge of size ``1 - sum(x)``.

        The wedges are plotted counterclockwise, by default starting from the
        x-axis.

        Parameters
        ----------
        x : 1D array-like
            The wedge sizes.

        explode : array-like, default: None
            If not *None*, is a ``len(x)`` array which specifies the fraction
            of the radius with which to offset each wedge.

        labels : list, default: None
            A sequence of strings providing the labels for each wedge

        colors : array-like, default: None
            A sequence of colors through which the pie chart will cycle.  If
            *None*, will use the colors in the currently active cycle.

        autopct : None or str or callable, default: None
            If not *None*, is a string or function used to label the wedges
            with their numeric value.  The label will be placed inside the
            wedge.  If it is a format string, the label will be ``fmt % pct``.
            If it is a function, it will be called.

        pctdistance : float, default: 0.6
            The ratio between the center of each pie slice and the start of
            the text generated by *autopct*.  Ignored if *autopct* is *None*.

        shadow : bool, default: False
            Draw a shadow beneath the pie.

        normalize: None or bool, default: None
            When *True*, always make a full pie by normalizing x so that
            ``sum(x) == 1``. *False* makes a partial pie if ``sum(x) <= 1``
            and raises a `ValueError` for ``sum(x) > 1``.

            When *None*, defaults to *True* if ``sum(x) >= 1`` and *False* if
            ``sum(x) < 1``.

            Please note that the previous default value of *None* is now
            deprecated, and the default will change to *True* in the next
            release. Please pass ``normalize=False`` explicitly if you want to
            draw a partial pie.

        labeldistance : float or None, default: 1.1
            The radial distance at which the pie labels are drawn.
            If set to ``None``, label are not drawn, but are stored for use in
            ``legend()``

        startangle : float, default: 0 degrees
            The angle by which the start of the pie is rotated,
            counterclockwise from the x-axis.

        radius : float, default: 1
            The radius of the pie.

        counterclock : bool, default: True
            Specify fractions direction, clockwise or counterclockwise.

        wedgeprops : dict, default: None
            Dict of arguments passed to the wedge objects making the pie.
            For example, you can pass in ``wedgeprops = {'linewidth': 3}``
            to set the width of the wedge border lines equal to 3.
            For more details, look at the doc/arguments of the wedge object.
            By default ``clip_on=False``.

        textprops : dict, default: None
            Dict of arguments to pass to the text objects.

        center : (float, float), default: (0, 0)
            The coordinates of the center of the chart.

        frame : bool, default: False
            Plot axes frame with the chart if true.

        rotatelabels : bool, default: False
            Rotate each label to the angle of the corresponding slice if true.

        Returns
        -------
        patches : list
            A sequence of `matplotlib.patches.Wedge` instances

        texts : list
            A list of the label `.Text` instances.

        autotexts : list
            A list of `.Text` instances for the numeric labels. This will only
            be returned if the parameter *autopct* is not *None*.

        Notes
        -----
        The pie chart will probably look best if the figure and axes are
        square, or the Axes aspect is equal.
        This method sets the aspect ratio of the axis to "equal".
        The axes aspect ratio can be controlled with `.Axes.set_aspect`.

        .. note::
            In addition to the above described arguments, this function can take
            a *data* keyword argument. If such a *data* argument is given,
            the following arguments can also be string ``s``, which is
            interpreted as ``data[s]`` (unless this raises an exception):
            *x*, *explode*, *labels*, *colors*.

            Objects passed as **data** must support item access (``data[s]``) and
            membership syntax (``s in data``).
    """

    def pie_explode(self):
        """set explode, labels, colors, rotationlabels"""
        x = [0.15, 0.32, 0.35, 0.18]
        explode = [0, 0.2, 0, 0]
        fig, ax = plt.subplots(1, 2)
        ax[0].pie(x=x, explode=explode, colors=('r', 'g', 'b', 'y'),
                  labels=['{:3.1f}%'.format(_x*100) for _x in x],
                  frame=True)
        ax[1].pie(x=x, explode=explode, colors=('r', 'g', 'b', 'y'),
                  labels=['{:3.1f}%'.format(_x*100) for _x in x],
                  rotatelabels=True)

    def pie_autopct(self):
        """set atuopct to str, formatstr, function"""
        x = [0.15, 0.32, 0.35, 0.18]
        fig, ax = plt.subplots(1, 3)
        ax[0].pie(x=x, autopct='Wedge')
        ax[0].set(xlabel='autopct:=str')
        ax[1].pie(x=x, autopct="%3.1f")
        ax[1].set(xlabel='autopct:="%3.1f"')
        ax[2].pie(x=x, autopct=lambda v: '{:2.2f}%'.format(v))
        ax[2].set(xlabel='autopct:=function')

    def pie_normalize(self):
        """set atuopct to str, formatstr, function"""
        x1 = [0.1, 0.3, 0.3, 0.1]
        x2 = [0.1, 0.3, 0.3, 0.8]
        fig, ax = plt.subplots(1, 3)
        ax[0].pie(x=x1, normalize=False)
        ax[0].set(xlabel='normalize:=False\nx = [0.1, 0.3, 0.3, 0.1]\nsum(x)=1')
        try:
            ax[1].pie(x=x2, normalize=False)
        except ValueError as e:
            ax[1].text(0.2, 0.5, 'ValueError')
            # ax[1].set(frameon=False)
        ax[1].set(xlabel='normalize:=False\nx = [0.1, 0.3, 0.3, 0.8]\nsum(x)>1')
        ax[2].pie(x=x2, normalize=True)
        ax[2].set(xlabel='normalize:=True\nx = [0.1, 0.3, 0.3, 0.8]\nsum(x)>1')


class DemoHist:

    """
    hist(x, bins=None, range=None, density=False, weights=None, cumulative=False, bottom=None, histtype='bar',
         align='mid', orientation='vertical', rwidth=None, log=False, color=None, label=None, stacked=False, *,
         data=None, **kwargs)

        Plot a histogram.

        Compute and draw the histogram of *x*.  The return value is a tuple
        (*n*, *bins*, *patches*) or ([*n0*, *n1*, ...], *bins*, [*patches0*,
        *patches1*, ...]) if the input contains multiple data.  See the
        documentation of the *weights* parameter to draw a histogram of
        already-binned data.

        Multiple data can be provided via *x* as a list of datasets
        of potentially different length ([*x0*, *x1*, ...]), or as
        a 2-D ndarray in which each column is a dataset.  Note that
        the ndarray form is transposed relative to the list form.

        Masked arrays are not supported.

        The *bins*, *range*, *weights*, and *density* parameters behave as in
        `numpy.histogram`.

        Parameters
        ----------
        x : (n,) array or sequence of (n,) arrays
            Input values, this takes either a single array or a sequence of
            arrays which are not required to be of the same length.

        bins : int or sequence or str, default: :rc:`hist.bins`
            If *bins* is an integer, it defines the number of equal-width bins
            in the range.

            If *bins* is a sequence, it defines the bin edges, including the
            left edge of the first bin and the right edge of the last bin;
            in this case, bins may be unequally spaced.  All but the last
            (righthand-most) bin is half-open.  In other words, if *bins* is::

                [1, 2, 3, 4]

            then the first bin is ``[1, 2)`` (including 1, but excluding 2) and
            the second ``[2, 3)``.  The last bin, however, is ``[3, 4]``, which
            *includes* 4.

            If *bins* is a string, it is one of the binning strategies
            supported by `numpy.histogram_bin_edges`: 'auto', 'fd', 'doane',
            'scott', 'stone', 'rice', 'sturges', or 'sqrt'.

        range : tuple or None, default: None
            The lower and upper range of the bins. Lower and upper outliers
            are ignored. If not provided, *range* is ``(x.min(), x.max())``.
            Range has no effect if *bins* is a sequence.

            If *bins* is a sequence or *range* is specified, autoscaling
            is based on the specified bin range instead of the
            range of x.

        density : bool, default: False
            If ``True``, draw and return a probability density: each bin
            will display the bin's raw count divided by the total number of
            counts *and the bin width*
            (``density = counts / (sum(counts) * np.diff(bins))``),
            so that the area under the histogram integrates to 1
            (``np.sum(density * np.diff(bins)) == 1``).

            If *stacked* is also ``True``, the sum of the histograms is
            normalized to 1.

        weights : (n,) array-like or None, default: None
            An array of weights, of the same shape as *x*.  Each value in
            *x* only contributes its associated weight towards the bin count
            (instead of 1).  If *density* is ``True``, the weights are
            normalized, so that the integral of the density over the range
            remains 1.

            This parameter can be used to draw a histogram of data that has
            already been binned, e.g. using `numpy.histogram` (by treating each
            bin as a single point with a weight equal to its count) ::

                counts, bins = np.histogram(data)
                plt.hist(bins[:-1], bins, weights=counts)

            (or you may alternatively use `~.bar()`).

        cumulative : bool or -1, default: False
            If ``True``, then a histogram is computed where each bin gives the
            counts in that bin plus all bins for smaller values. The last bin
            gives the total number of datapoints.

            If *density* is also ``True`` then the histogram is normalized such
            that the last bin equals 1.

            If *cumulative* is a number less than 0 (e.g., -1), the direction
            of accumulation is reversed.  In this case, if *density* is also
            ``True``, then the histogram is normalized such that the first bin
            equals 1.

        bottom : array-like, scalar, or None, default: None
            Location of the bottom of each bin, ie. bins are drawn from
            ``bottom`` to ``bottom + hist(x, bins)`` If a scalar, the bottom
            of each bin is shifted by the same amount. If an array, each bin
            is shifted independently and the length of bottom must match the
            number of bins. If None, defaults to 0.

        histtype : {'bar', 'barstacked', 'step', 'stepfilled'}, default: 'bar'
            The type of histogram to draw.

            - 'bar' is a traditional bar-type histogram.  If multiple data
              are given the bars are arranged side by side.
            - 'barstacked' is a bar-type histogram where multiple
              data are stacked on top of each other.
            - 'step' generates a lineplot that is by default unfilled.
            - 'stepfilled' generates a lineplot that is by default filled.

        align : {'left', 'mid', 'right'}, default: 'mid'
            The horizontal alignment of the histogram bars.

            - 'left': bars are centered on the left bin edges.
            - 'mid': bars are centered between the bin edges.
            - 'right': bars are centered on the right bin edges.

        orientation : {'vertical', 'horizontal'}, default: 'vertical'
            If 'horizontal', `~.Axes.barh` will be used for bar-type histograms
            and the *bottom* kwarg will be the left edges.

        rwidth : float or None, default: None
            The relative width of the bars as a fraction of the bin width.  If
            ``None``, automatically compute the width.

            Ignored if *histtype* is 'step' or 'stepfilled'.

        log : bool, default: False
            If ``True``, the histogram axis will be set to a log scale. If
            *log* is ``True`` and *x* is a 1D array, empty bins will be
            filtered out and only the non-empty ``(n, bins, patches)``
            will be returned.

        color : color or array-like of colors or None, default: None
            Color or sequence of colors, one per dataset.  Default (``None``)
            uses the standard line color sequence.

        label : str or None, default: None
            String, or sequence of strings to match multiple datasets.  Bar
            charts yield multiple patches per dataset, but only the first gets
            the label, so that `~.Axes.legend` will work as expected.

        stacked : bool, default: False
            If ``True``, multiple data are stacked on top of each other If
            ``False`` multiple data are arranged side by side if histtype is
            'bar' or on top of each other if histtype is 'step'

        Returns
        -------
        n : array or list of arrays
            The values of the histogram bins. See *density* and *weights* for a
            description of the possible semantics.  If input *x* is an array,
            then this is an array of length *nbins*. If input is a sequence of
            arrays ``[data1, data2, ...]``, then this is a list of arrays with
            the values of the histograms for each of the arrays in the same
            order.  The dtype of the array *n* (or of its element arrays) will
            always be float even if no weighting or normalization is used.

        bins : array
            The edges of the bins. Length nbins + 1 (nbins left edges and right
            edge of last bin).  Always a single array even when multiple data
            sets are passed in.

        patches : `.BarContainer` or list of a single `.Polygon` or list of such objects
            Container of individual artists used to create the histogram
            or list of such containers if there are multiple input datasets.

        Other Parameters
        ----------------
        **kwargs
            `~matplotlib.patches.Patch` properties

        See Also
        --------
        hist2d : 2D histograms

        Notes
        -----
        For large numbers of bins (>1000), 'step' and 'stepfilled' can be
        significantly faster than 'bar' and 'barstacked'.

        .. note::
            In addition to the above described arguments, this function can take
            a *data* keyword argument. If such a *data* argument is given,
            the following arguments can also be string ``s``, which is
            interpreted as ``data[s]`` (unless this raises an exception):
            *x*, *weights*.

            Objects passed as **data** must support item access (``data[s]``) and
            membership syntax (``s in data``).
    """

    # Numpy function histogram_bin_edges
    """
    histogram_bin_edges(a, bins=10, range=None, weights=None)
    
    Function to calculate only the edges of the bins used by the `histogram`
    function.
    
    Parameters
    ----------
    a : array_like
        Input data. The histogram is computed over the flattened array.
    bins : int or sequence of scalars or str, optional
        If `bins` is an int, it defines the number of equal-width
        bins in the given range (10, by default). If `bins` is a
        sequence, it defines the bin edges, including the rightmost
        edge, allowing for non-uniform bin widths.
    
        If `bins` is a string from the list below, `histogram_bin_edges` will use
        the method chosen to calculate the optimal bin width and
        consequently the number of bins (see `Notes` for more detail on
        the estimators) from the data that falls within the requested
        range. While the bin width will be optimal for the actual data
        in the range, the number of bins will be computed to fill the
        entire range, including the empty portions. For visualisation,
        using the 'auto' option is suggested. Weighted data is not
        supported for automated bin size selection.
    
        'auto'
            Maximum of the 'sturges' and 'fd' estimators. Provides good
            all around performance.
    
        'fd' (Freedman Diaconis Estimator)
            Robust (resilient to outliers) estimator that takes into
            account data variability and data size.
    
        'doane'
            An improved version of Sturges' estimator that works better
            with non-normal datasets.
    
        'scott'
            Less robust estimator that that takes into account data
            variability and data size.
    
        'stone'
            Estimator based on leave-one-out cross-validation estimate of
            the integrated squared error. Can be regarded as a generalization
            of Scott's rule.
    
        'rice'
            Estimator does not take variability into account, only data
            size. Commonly overestimates number of bins required.
    
        'sturges'
            R's default method, only accounts for data size. Only
            optimal for gaussian data and underestimates number of bins
            for large non-gaussian datasets.
    
        'sqrt'
            Square root (of data size) estimator, used by Excel and
            other programs for its speed and simplicity.
    
    range : (float, float), optional
        The lower and upper range of the bins.  If not provided, range
        is simply ``(a.min(), a.max())``.  Values outside the range are
        ignored. The first element of the range must be less than or
        equal to the second. `range` affects the automatic bin
        computation as well. While bin width is computed to be optimal
        based on the actual data within `range`, the bin count will fill
        the entire range including portions containing no data.
    
    weights : array_like, optional
        An array of weights, of the same shape as `a`.  Each value in
        `a` only contributes its associated weight towards the bin count
        (instead of 1). This is currently not used by any of the bin estimators,
        but may be in the future.
    
    Returns
    -------
    bin_edges : array of dtype float
        The edges to pass into `histogram`
    
    See Also
    --------
    histogram
    
    Notes
    -----
    The methods to estimate the optimal number of bins are well founded
    in literature, and are inspired by the choices R provides for
    histogram visualisation. Note that having the number of bins
    proportional to :math:`n^{1/3}` is asymptotically optimal, which is
    why it appears in most estimators. These are simply plug-in methods
    that give good starting points for number of bins. In the equations
    below, :math:`h` is the binwidth and :math:`n_h` is the number of
    bins. All estimators that compute bin counts are recast to bin width
    using the `ptp` of the data. The final bin count is obtained from
    ``np.round(np.ceil(range / h))``. The final bin width is often less 
    than what is returned by the estimators below.
    
    'auto' (maximum of the 'sturges' and 'fd' estimators)
        A compromise to get a good value. For small datasets the Sturges
        value will usually be chosen, while larger datasets will usually
        default to FD.  Avoids the overly conservative behaviour of FD
        and Sturges for small and large datasets respectively.
        Switchover point is usually :math:`a.size \approx 1000`.
    
    'fd' (Freedman Diaconis Estimator)
        .. math:: h = 2 \frac{IQR}{n^{1/3}}
    
        The binwidth is proportional to the interquartile range (IQR)
        and inversely proportional to cube root of a.size. Can be too
        conservative for small datasets, but is quite good for large
        datasets. The IQR is very robust to outliers.
    
    'scott'
        .. math:: h = \sigma \sqrt[3]{\frac{24 * \sqrt{\pi}}{n}}
    
        The binwidth is proportional to the standard deviation of the
        data and inversely proportional to cube root of ``x.size``. Can
        be too conservative for small datasets, but is quite good for
        large datasets. The standard deviation is not very robust to
        outliers. Values are very similar to the Freedman-Diaconis
        estimator in the absence of outliers.
    
    'rice'
        .. math:: n_h = 2n^{1/3}
    
        The number of bins is only proportional to cube root of
        ``a.size``. It tends to overestimate the number of bins and it
        does not take into account data variability.
    
    'sturges'
        .. math:: n_h = \log _{2}n+1
    
        The number of bins is the base 2 log of ``a.size``.  This
        estimator assumes normality of data and is too conservative for
        larger, non-normal datasets. This is the default method in R's
        ``hist`` method.
    
    'doane'
        .. math:: n_h = 1 + \log_{2}(n) +
                        \log_{2}(1 + \frac{|g_1|}{\sigma_{g_1}})
    
            g_1 = mean[(\frac{x - \mu}{\sigma})^3]
    
            \sigma_{g_1} = \sqrt{\frac{6(n - 2)}{(n + 1)(n + 3)}}
    
        An improved version of Sturges' formula that produces better
        estimates for non-normal datasets. This estimator attempts to
        account for the skew of the data.
    
    'sqrt'
        .. math:: n_h = \sqrt n
    
        The simplest and fastest estimator. Only takes into account the
        data size.
    
    Examples
    --------
    >>> arr = np.array([0, 0, 0, 1, 2, 3, 3, 4, 5])
    >>> np.histogram_bin_edges(arr, bins='auto', range=(0, 1))
    array([0.  , 0.25, 0.5 , 0.75, 1.  ])
    >>> np.histogram_bin_edges(arr, bins=2)
    array([0. , 2.5, 5. ])
    
    For consistency with histogram, an array of pre-computed bins is
    passed through unmodified:
    
    >>> np.histogram_bin_edges(arr, [1, 2])
    array([1, 2])
    
    This function allows one set of bins to be computed, and reused across
    multiple histograms:
    
    >>> shared_bins = np.histogram_bin_edges(arr, bins='auto')
    >>> shared_bins
    array([0., 1., 2., 3., 4., 5.])
    
    >>> group_id = np.array([0, 1, 1, 0, 1, 1, 0, 1, 1])
    >>> hist_0, _ = np.histogram(arr[group_id == 0], bins=shared_bins)
    >>> hist_1, _ = np.histogram(arr[group_id == 1], bins=shared_bins)
    
    >>> hist_0; hist_1
    array([1, 1, 0, 1, 0])
    array([2, 0, 1, 1, 2])
    
    Which gives more easily comparable results than using separate bins for
    each histogram:
    
    >>> hist_0, bins_0 = np.histogram(arr[group_id == 0], bins='auto')
    >>> hist_1, bins_1 = np.histogram(arr[group_id == 1], bins='auto')
    >>> hist_0; hist_1
    array([1, 1, 1])
    array([2, 1, 1, 2])
    >>> bins_0; bins_1
    array([0., 1., 2., 3.])
    array([0.  , 1.25, 2.5 , 3.75, 5.  ])

    """

    def hist1(self):
        data = [1, 2, 2, 3, 5, 7, 7.5, 8, 9, 10]
        fig, ax = plt.subplots()
        n, bins, patches = ax.hist(x=data, bins=4, rwidth=0.5)
        print(
            " >>> data = [1, 2, 2, 3, 5, 7, 7.5, 8, 9, 10]\n"
            " >>> fig, ax = plt.subplots()\n"
            " >>> n, bins, patches = ax.hist(x=data, bins=3, rwidth=.5)\n"
            r" >>> print(f'n:{n}\nbins:{bins}\npatches: {patches}')"
            "\n"
            f"n: {n}\n"
            f"bins: {bins}\n"
            f"patches: {patches}"
        )

    def hist2(self):
        data = [1, 2, 2, 3, 5, 7, 7.5, 8, 9, 10]
        fig, ax = plt.subplots()
        n, bins, patches = ax.hist(x=data, bins=(0.5, 3, 5, 10), rwidth=0.5)
        print(
            " >>> data = [1, 2, 2, 3, 5, 7, 7.5, 8, 9, 10]\n"
            " >>> fig, ax = plt.subplots()\n"
            " >>> n, bins, patches = ax.hist(x=data, bins=(0.5, 3, 5, 10), rwidth=.5)\n"
            r" >>> print(f'n:{n}\nbins:{bins}\npatches: {patches}')"
            "\n"
            f"n: {n}\n"
            f"bins: {bins}\n"
            f"patches: {patches}"
        )

    def hist3(self):
        """使用累积方式cumulative=True"""
        data = [1, 2, 2, 3, 5, 7, 7.5, 8, 9, 10]
        fig, ax = plt.subplots()
        n, bins, patches = ax.hist(x=data, bins=3, rwidth=0.5, cumulative=True)
        print(
            " >>> data = [1, 2, 2, 3, 5, 7, 7.5, 8, 9, 10]\n"
            " >>> fig, ax = plt.subplots()\n"
            " >>> n, bins, patches = ax.hist(x=data, bins=3, rwidth=.5)\n"
            r" >>> print(f'n:{n}\nbins:{bins}\npatches: {patches}')"
            "\n"
            f"n: {n}\n"
            f"bins: {bins}\n"
            f"patches: {patches}"
        )

    def hist4(self):
        data1 = [1, 2, 2, 3, 5, 7, 7.5, 8, 9, 10]
        data2 = [1, 1, 2, 5, 6, 7, 7, 8, 10, 10]
        fig, ax = plt.subplots()
        n, bins, patches = ax.hist(x=(data1, data2), bins=(0.5, 3, 5, 10), histtype='barstacked', rwidth=0.5)
        print(
            " >>> data1 = [1, 2, 2, 3, 5, 7, 7.5, 8, 9, 10]\n"
            " >>> data2 = [1, 1, 2, 5, 6, 7, 7, 8, 10, 10]\n"
            " >>> fig, ax = plt.subplots()\n"
            " >>> n, bins, patches = ax.hist(x=data, bins=(0.5, 3, 5, 10), histtype='barstacked', rwidth=.5)\n"
            r" >>> print(f'n:{n}\nbins:{bins}\npatches: {patches}')"
            "\n"
            f"n: {n}\n"
            f"bins: {bins}\n"
            f"patches: {patches}"
        )


class DemoSetting:

    def plt_set_style(self):
        """
        use(style)
            Use matplotlib style settings from a style specification.

            The style name of 'default' is reserved for reverting back to
            the default style settings.

            Parameters
            ----------
            style : str, dict, or list
                A style specification. Valid options are:

                +------+-------------------------------------------------------------+
                | str  | The name of a style or a path/URL to a style file. For a    |
                |      | list of available style names, see `style.available`.       |
                +------+-------------------------------------------------------------+
                | dict | Dictionary with valid key/value pairs for                   |
                |      | `matplotlib.rcParams`.                                      |
                +------+-------------------------------------------------------------+
                | list | A list of style specifiers (str or dict) applied from first |
                |      | to last in the list.                                        |
                +------+-------------------------------------------------------------+
        """
        fig = plt.figure('bmh')

    def plt_rcparams(self):
        """
class RcParams(collections.abc.MutableMapping, builtins.dict)
 |  RcParams(*args, **kwargs)
 |
 |  A dictionary object including validation
 |
 |  validating functions are defined and associated with rc parameters in
 |  :mod:`matplotlib.rcsetup`
 |
 |  Method resolution order:
 |      RcParams
 |      collections.abc.MutableMapping
 |      collections.abc.Mapping
 |      collections.abc.Collection
 |      collections.abc.Sized
 |      collections.abc.Iterable
 |      collections.abc.Container
 |      builtins.dict
 |      builtins.object
 |
 |  Methods defined here:
        """

        # rcParams.keys
        from cycler import cycler
        rckeys = {
          '_internal.classic_mode': False,
          'agg.path.chunksize': 0,
          'animation.avconv_args': [],
          'animation.avconv_path': 'avconv',
          'animation.bitrate': -1,
          'animation.codec': 'h264',
          'animation.convert_args': [],
          'animation.convert_path': 'convert',
          'animation.embed_limit': 20.0,
          'animation.ffmpeg_args': [],
          'animation.ffmpeg_path': 'ffmpeg',
          'animation.frame_format': 'png',
          'animation.html': 'none',
          'animation.html_args': [],
          'animation.writer': 'ffmpeg',
          'axes.autolimit_mode': 'data',
          'axes.axisbelow': 'line',
          'axes.edgecolor': 'black',
          'axes.facecolor': 'white',
          'axes.formatter.limits': [-7, 7],
          'axes.formatter.min_exponent': 0,
          'axes.formatter.offset_threshold': 4,
          'axes.formatter.use_locale': False,
          'axes.formatter.use_mathtext': False,
          'axes.formatter.useoffset': True,
          'axes.grid': False,
          'axes.grid.axis': 'both',
          'axes.grid.which': 'major',
          'axes.labelcolor': 'black',
          'axes.labelpad': 4.0,
          'axes.labelsize': 'medium',
          'axes.labelweight': 'normal',
          'axes.linewidth': 0.8,
          'axes.prop_cycle': cycler('color', ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b',
                                              '#e377c2', '#7f7f7f', '#bcbd22', '#17becf']),
          'axes.spines.bottom': True,
          'axes.spines.left': True,
          'axes.spines.right': True,
          'axes.spines.top': True,
          'axes.titlepad': 6.0,
          'axes.titlesize': 'large',
          'axes.titleweight': 'normal',
          'axes.unicode_minus': True,
          'axes.xmargin': 0.05,
          'axes.ymargin': 0.05,
          'axes3d.grid': True,
          'backend': 'Qt5Agg',
          'backend_fallback': True,
          'boxplot.bootstrap': None,
          'boxplot.boxprops.color': 'black',
          'boxplot.boxprops.linestyle': '-',
          'boxplot.boxprops.linewidth': 1.0,
          'boxplot.capprops.color': 'black',
          'boxplot.capprops.linestyle': '-',
          'boxplot.capprops.linewidth': 1.0,
          'boxplot.flierprops.color': 'black',
          'boxplot.flierprops.linestyle': 'none',
          'boxplot.flierprops.linewidth': 1.0,
          'boxplot.flierprops.marker': 'o',
          'boxplot.flierprops.markeredgecolor': 'black',
          'boxplot.flierprops.markeredgewidth': 1.0,
          'boxplot.flierprops.markerfacecolor': 'none',
          'boxplot.flierprops.markersize': 6.0,
          'boxplot.meanline': False,
          'boxplot.meanprops.color': 'C2',
          'boxplot.meanprops.linestyle': '--',
          'boxplot.meanprops.linewidth': 1.0,
          'boxplot.meanprops.marker': '^',
          'boxplot.meanprops.markeredgecolor': 'C2',
          'boxplot.meanprops.markerfacecolor': 'C2',
          'boxplot.meanprops.markersize': 6.0,
          'boxplot.medianprops.color': 'C1',
          'boxplot.medianprops.linestyle': '-',
          'boxplot.medianprops.linewidth': 1.0,
          'boxplot.notch': False,
          'boxplot.patchartist': False,
          'boxplot.showbox': True,
          'boxplot.showcaps': True,
          'boxplot.showfliers': True,
          'boxplot.showmeans': False,
          'boxplot.vertical': True,
          'boxplot.whiskerprops.color': 'black',
          'boxplot.whiskerprops.linestyle': '-',
          'boxplot.whiskerprops.linewidth': 1.0,
          'boxplot.whiskers': 1.5,
          'contour.corner_mask': True,
          'contour.negative_linestyle': 'dashed',
          'datapath': 'D:\\Anaconda3\\lib\\site-packages\\matplotlib\\mpl-data',
          'date.autoformatter.day': '%Y-%m-%d',
          'date.autoformatter.hour': '%m-%d %H',
          'date.autoformatter.microsecond': '%M:%S.%f',
          'date.autoformatter.minute': '%d %H:%M',
          'date.autoformatter.month': '%Y-%m',
          'date.autoformatter.second': '%H:%M:%S',
          'date.autoformatter.year': '%Y',
          'docstring.hardcopy': False,
          'errorbar.capsize': 0.0,
          'examples.directory': '',
          'figure.autolayout': False,
          'figure.constrained_layout.h_pad': 0.04167,
          'figure.constrained_layout.hspace': 0.02,
          'figure.constrained_layout.use': False,
          'figure.constrained_layout.w_pad': 0.04167,
          'figure.constrained_layout.wspace': 0.02,
          'figure.dpi': 100.0,
          'figure.edgecolor': 'white',
          'figure.facecolor': 'white',
          'figure.figsize': [6.4, 4.8],
          'figure.frameon': True,
          'figure.max_open_warning': 20,
          'figure.subplot.bottom': 0.11,
          'figure.subplot.hspace': 0.2,
          'figure.subplot.left': 0.125,
          'figure.subplot.right': 0.9,
          'figure.subplot.top': 0.88,
          'figure.subplot.wspace': 0.2,
          'figure.titlesize': 'large',
          'figure.titleweight': 'normal',
          'font.cursive': ['Apple Chancery',
                           'Textile',
                           'Zapf Chancery',
                           'Sand',
                           'Script MT',
                           'Felipa',
                           'cursive'],
          'font.family': ['sans-serif'],
          'font.fantasy': ['Comic Sans MS',
                           'Chicago',
                           'Charcoal',
                           'Impact',
                           'Western',
                           'Humor Sans',
                           'xkcd',
                           'fantasy'],
          'font.monospace': ['DejaVu Sans Mono',
                             'Bitstream Vera Sans Mono',
                             'Computer Modern Typewriter',
                             'Andale Mono',
                             'Nimbus Mono L',
                             'Courier New',
                             'Courier',
                             'Fixed',
                             'Terminal',
                             'monospace'],
          'font.sans-serif': ['DejaVu Sans',
                              'Bitstream Vera Sans',
                              'Computer Modern Sans Serif',
                              'Lucida Grande',
                              'Verdana',
                              'Geneva',
                              'Lucid',
                              'Arial',
                              'Helvetica',
                              'Avant Garde',
                              'sans-serif'],
          'font.serif': ['DejaVu Serif',
                         'Bitstream Vera Serif',
                         'Computer Modern Roman',
                         'New Century Schoolbook',
                         'Century Schoolbook L',
                         'Utopia',
                         'ITC Bookman',
                         'Bookman',
                         'Nimbus Roman No9 L',
                         'Times New Roman',
                         'Times',
                         'Palatino',
                         'Charter',
                         'serif'],
          'font.size': 10.0,
          'font.stretch': 'normal',
          'font.style': 'normal',
          'font.variant': 'normal',
          'font.weight': 'normal',
          'grid.alpha': 1.0,
          'grid.color': '#b0b0b0',
          'grid.linestyle': '-',
          'grid.linewidth': 0.8,
          'hatch.color': 'black',
          'hatch.linewidth': 1.0,
          'hist.bins': 10,
          'image.aspect': 'equal',
          'image.cmap': 'viridis',
          'image.composite_image': True,
          'image.interpolation': 'nearest',
          'image.lut': 256,
          'image.origin': 'upper',
          'image.resample': True,
          'interactive': True,
          'keymap.all_axes': ['a'],
          'keymap.back': ['left', 'c', 'backspace', 'MouseButton.BACK'],
          'keymap.copy': ['ctrl+c', 'cmd+c'],
          'keymap.forward': ['right', 'v', 'MouseButton.FORWARD'],
          'keymap.fullscreen': ['f', 'ctrl+f'],
          'keymap.grid': ['g'],
          'keymap.grid_minor': ['G'],
          'keymap.help': ['f1'],
          'keymap.home': ['h', 'r', 'home'],
          'keymap.pan': ['p'],
          'keymap.quit': ['ctrl+w', 'cmd+w', 'q'],
          'keymap.quit_all': ['W', 'cmd+W', 'Q'],
          'keymap.save': ['s', 'ctrl+s'],
          'keymap.xscale': ['k', 'L'],
          'keymap.yscale': ['l'],
          'keymap.zoom': ['o'],
          'legend.borderaxespad': 0.5,
          'legend.borderpad': 0.4,
          'legend.columnspacing': 2.0,
          'legend.edgecolor': '0.8',
          'legend.facecolor': 'inherit',
          'legend.fancybox': True,
          'legend.fontsize': 'medium',
          'legend.framealpha': 0.8,
          'legend.frameon': True,
          'legend.handleheight': 0.7,
          'legend.handlelength': 2.0,
          'legend.handletextpad': 0.8,
          'legend.labelspacing': 0.5,
          'legend.loc': 'best',
          'legend.markerscale': 1.0,
          'legend.numpoints': 1,
          'legend.scatterpoints': 1,
          'legend.shadow': False,
          'legend.title_fontsize': None,
          'lines.antialiased': True,
          'lines.color': 'C0',
          'lines.dash_capstyle': 'butt',
          'lines.dash_joinstyle': 'round',
          'lines.dashdot_pattern': [6.4, 1.6, 1.0, 1.6],
          'lines.dashed_pattern': [3.7, 1.6],
          'lines.dotted_pattern': [1.0, 1.65],
          'lines.linestyle': '-',
          'lines.linewidth': 1.5,
          'lines.marker': 'None',
          'lines.markeredgecolor': 'auto',
          'lines.markeredgewidth': 1.0,
          'lines.markerfacecolor': 'auto',
          'lines.markersize': 6.0,
          'lines.scale_dashes': True,
          'lines.solid_capstyle': 'projecting',
          'lines.solid_joinstyle': 'round',
          'markers.fillstyle': 'full',
          'mathtext.bf': 'sans:bold',
          'mathtext.cal': 'cursive',
          'mathtext.default': 'it',
          'mathtext.fallback_to_cm': True,
          'mathtext.fontset': 'dejavusans',
          'mathtext.it': 'sans:italic',
          'mathtext.rm': 'sans',
          'mathtext.sf': 'sans',
          'mathtext.tt': 'monospace',
          'patch.antialiased': True,
          'patch.edgecolor': 'black',
          'patch.facecolor': 'C0',
          'patch.force_edgecolor': False,
          'patch.linewidth': 1.0,
          'path.effects': [],
          'path.simplify': True,
          'path.simplify_threshold': 0.1111111111111111,
          'path.sketch': None,
          'path.snap': True,
          'pdf.compression': 6,
          'pdf.fonttype': 3,
          'pdf.inheritcolor': False,
          'pdf.use14corefonts': False,
          'pgf.preamble': '',
          'pgf.rcfonts': True,
          'pgf.texsystem': 'xelatex',
          'polaraxes.grid': True,
          'ps.distiller.res': 6000,
          'ps.fonttype': 3,
          'ps.papersize': 'letter',
          'ps.useafm': False,
          'ps.usedistiller': False,
          'savefig.bbox': None,
          'savefig.directory': '~',
          'savefig.dpi': 'figure',
          'savefig.edgecolor': 'white',
          'savefig.facecolor': 'white',
          'savefig.format': 'png',
          'savefig.frameon': True,
          'savefig.jpeg_quality': 95,
          'savefig.orientation': 'portrait',
          'savefig.pad_inches': 0.1,
          'savefig.transparent': False,
          'scatter.edgecolors': 'face',
          'scatter.marker': 'o',
          'svg.fonttype': 'path',
          'svg.hashsalt': None,
          'svg.image_inline': True,
          'text.antialiased': True,
          'text.color': 'black',
          'text.hinting': 'auto',
          'text.hinting_factor': 8,
          'text.latex.preamble': '',
          'text.latex.preview': False,
          'text.latex.unicode': True,
          'text.usetex': False,
          'timezone': 'UTC',
          'tk.window_focus': False,
          'toolbar': 'toolbar2',
          'verbose.fileo': 'sys.stdout',
          'verbose.level': 'silent',
          'webagg.address': '127.0.0.1',
          'webagg.open_in_browser': True,
          'webagg.port': 8988,
          'webagg.port_retries': 50,
          'xtick.alignment': 'center',
          'xtick.bottom': True,
          'xtick.color': 'black',
          'xtick.direction': 'out',
          'xtick.labelbottom': True,
          'xtick.labelsize': 'medium',
          'xtick.labeltop': False,
          'xtick.major.bottom': True,
          'xtick.major.pad': 3.5,
          'xtick.major.size': 3.5,
          'xtick.major.top': True,
          'xtick.major.width': 0.8,
          'xtick.minor.bottom': True,
          'xtick.minor.pad': 3.4,
          'xtick.minor.size': 2.0,
          'xtick.minor.top': True,
          'xtick.minor.visible': False,
          'xtick.minor.width': 0.6,
          'xtick.top': False,
          'ytick.alignment': 'center_baseline',
          'ytick.color': 'black',
          'ytick.direction': 'out',
          'ytick.labelleft': True,
          'ytick.labelright': False,
          'ytick.labelsize': 'medium',
          'ytick.left': True,
          'ytick.major.left': True,
          'ytick.major.pad': 3.5,
          'ytick.major.right': True,
          'ytick.major.size': 3.5,
          'ytick.major.width': 0.8,
          'ytick.minor.left': True,
          'ytick.minor.pad': 3.4,
          'ytick.minor.right': True,
          'ytick.minor.size': 2.0,
          'ytick.minor.visible': False,
          'ytick.minor.width': 0.6,
          'ytick.right': False}

    @staticmethod
    def set_globl_params():
        plt.rcParams['font.sans-serif'] = 'SimHei'
        plt.rcParams['axes.unicode_minus'] = False
        font = {'weight': 'bold', 'size': 12, 'sans-serif': 'SimHei'}
        plt.rc('font', **font)
        # fig, ax = plt.subplots()
        # ax.plot(range(10), np.sin(range(10)), 'go--', label='sin')
        # ax.scatter(np.arange(0, 10, 0.1), np.cos(np.arange(0, 10, 0.1)), color='purple', label='cos')
        # ax.set_xlabel('time')
        # ax.set_ylabel('wave')
        # plt.legend()


class DemoCycler:

    @staticmethod
    def set_cycler_color():
        # cycler
        """
        cycler(*args, **kwargs)
            Create a new `Cycler` object from a single positional argument,
            a pair of positional arguments, or the combination of keyword arguments.
            
            cycler(arg)
            cycler(label1=itr1[, label2=iter2[, ...]])
            cycler(label, itr)
            
            Form 1 simply copies a given `Cycler` object.
            
            Form 2 composes a `Cycler` as an inner product of the
            pairs of keyword arguments. In other words, all of the
            iterables are cycled simultaneously, as if through zip().
            
            Form 3 creates a `Cycler` from a label and an iterable.
            This is useful for when the label cannot be a keyword argument
            (e.g., an integer or a name that has a space in it).
            
            Parameters
            ----------
            arg : Cycler
                Copy constructor for Cycler (does a shallow copy of iterables).
            
            label : name
                The property key. In the 2-arg form of the function,
                the label can be any hashable object. In the keyword argument
                form of the function, it must be a valid python identifier.
            
            itr : iterable
                Finite length iterable of the property values.
                Can be a single-property `Cycler` that would
                be like a key change, but as a shallow copy.
            
            Returns
            -------
            cycler : Cycler
                New `Cycler` for the given property        
        """

        # Cycler
        """
        class Cycler(builtins.object)
         |  Cycler(left, right=None, op=None)
         |  
         |  Composable cycles
         |  
         |  This class has compositions methods:
         |  
         |  ``+``
         |    for 'inner' products (zip)
         |  
         |  ``+=``
         |    in-place ``+``
         |  
         |  ``*``
         |    for outer products (itertools.product) and integer multiplication
         |  
         |  ``*=``
         |    in-place ``*``
         |  
         |  and supports basic slicing via ``[]``
         |  
         |  Parameters
         |  ----------
         |  left : Cycler or None
         |      The 'left' cycler
         |  
         |  right : Cycler or None
         |      The 'right' cycler
         |  
         |  op : func or None
         |      Function which composes the 'left' and 'right' cyclers.
         |  
         |  Methods defined here:
         |  
         |  __add__(self, other)
         |      Pair-wise combine two equal length cycles (zip)
         |      
         |      Parameters
         |      ----------
         |      other : Cycler
         |         The second Cycler
         |  
         |  __call__(self)
         |      Call self as a function.
         |  
         |  __eq__(self, other)
         |      Check equality
         |  
         |  __getitem__(self, key)
         |  
         |  __iadd__(self, other)
         |      In-place pair-wise combine two equal length cycles (zip)
         |      
         |      Parameters
         |      ----------
         |      other : Cycler
         |         The second Cycler
         |  
         |  __imul__(self, other)
         |      In-place outer product of two cycles (`itertools.product`)
         |      
         |      Parameters
         |      ----------
         |      other : Cycler
         |         The second Cycler
         |  
         |  __init__(self, left, right=None, op=None)
         |      Semi-private init
         |      
         |      Do not use this directly, use `cycler` function instead.
         |  
         |  __iter__(self)
         |  
         |  __len__(self)
         |  
         |  __mul__(self, other)
         |      Outer product of two cycles (`itertools.product`) or integer
         |      multiplication.
         |      
         |      Parameters
         |      ----------
         |      other : Cycler or int
         |         The second Cycler or integer
         |  
         |  __repr__(self)
         |      Return repr(self).
         |  
         |  __rmul__(self, other)
         |  
         |  by_key(self)
         |      Values by key
         |      
         |      This returns the transposed values of the cycler.  Iterating
         |      over a `Cycler` yields dicts with a single value for each key,
         |      this method returns a `dict` of `list` which are the values
         |      for the given key.
         |      
         |      The returned value can be used to create an equivalent `Cycler`
         |      using only `+`.
         |      
         |      Returns
         |      -------
         |      transpose : dict
         |          dict of lists of the values for each key.
         |  
         |  change_key(self, old, new)
         |      Change a key in this cycler to a new name.
         |      Modification is performed in-place.
         |      
         |      Does nothing if the old key is the same as the new key.
         |      Raises a ValueError if the new key is already a key.
         |      Raises a KeyError if the old key isn't a key.
         |  
         |  concat(self, other)
         |      Concatenate this cycler and an other.
         |      
         |      The keys must match exactly.
         |      
         |      This returns a single Cycler which is equivalent to
         |      `itertools.chain(self, other)`
         |      
         |      Examples
         |      --------
         |      
         |      >>> num = cycler('a', range(3))
         |      >>> let = cycler('a', 'abc')
         |      >>> num.concat(let)
         |      cycler('a', [0, 1, 2, 'a', 'b', 'c'])
         |      
         |      Parameters
         |      ----------
         |      other : `Cycler`
         |          The `Cycler` to concatenate to this one.
         |      
         |      Returns
         |      -------
         |      ret : `Cycler`
         |          The concatenated `Cycler`
         |  
         |  simplify(self)
         |      Simplify the Cycler
         |      
         |      Returned as a composition using only sums (no multiplications)
         |      
         |      Returns
         |      -------
         |      simple : Cycler
         |          An equivalent cycler using only summation
         |  
         |  ----------------------------------------------------------------------
         |  Data descriptors defined here:
         |  
         |  __dict__
         |      dictionary for instance variables (if defined)
         |  
         |  __weakref__
         |      list of weak references to the object (if defined)
         |  
         |  keys
         |      The keys this Cycler knows about
         |  
         |  ----------------------------------------------------------------------
         |  Data and other attributes defined here:
         |  
         |  __hash__ = None
         """

        from cycler import cycler

        # 全局修改循环器：rcParams["axes.prop_cycle"]，
        # 对所有子图生效，在运行期间有效，重启解释器后需要重新设置
        new_cycler = cycler(color=['r', 'g', 'b', 'y'])
        plt.rc('axes', prop_cycle=new_cycler)
        cycler_dict = mpl.rcParams["axes.prop_cycle"].by_key()
        print(cycler_dict['color'])

        fig, (ax0, ax1) = plt.subplots(nrows=2)
        for i in range(7):
            ax0.plot([i, i])

        # 使用Axes方法，只影响子图内绘图
        # 设置线宽、颜色循环器组合，循环器支持加法合成
        custom_cycler1 = cycler(lw=[1, 2, 3, 4])
        custom_cycler2 = cycler(color=['red', 'gray', 'purple', 'yellow'])
        ax1.set_prop_cycle(custom_cycler1+custom_cycler2)
        # for i in range(5):
        #     ax1.plot([i, i])
        ax1.pie([1]*4)

        print(plt.rcParams["axes.prop_cycle"])
        print([next(ax1._get_lines.prop_cycler) for i in range(5)])

        plt.show()

    @staticmethod
    def use_cycler():
        fig, ax = plt.subplots()
        cycler = plt.rcParams['axes.prop_cycle']

        cycler = plt.cycler(linewidth=[1, 3, 5, 7],
                            color=['r', 'g', 'y', 'purple'])
        ax.set_prop_cycle(cycler)

        for j in range(3):
            ax.plot([j, j], [0, 2])


class DemoPatch:

    """
class Patch(matplotlib.artist.Artist)
 |  Patch(edgecolor=None, facecolor=None, color=None, linewidth=None, linestyle=None, antialiased=None,
          hatch=None, fill=True, capstyle=None, joinstyle=None, **kwargs)
 |
 |  A patch is a 2D artist with a face color and an edge color.
 |
 |  If any of *edgecolor*, *facecolor*, *linewidth*, or *antialiased*
 |  are *None*, they default to their rc params setting.
 |
 |  Method resolution order:
 |      Patch
 |      matplotlib.artist.Artist
 |      builtins.object
 |
 |  Methods defined here:
 |
 |  __init__(self, edgecolor=None, facecolor=None, color=None, linewidth=None, linestyle=None, antialiased=None,
             hatch=None, fill=True, capstyle=None, joinstyle=None, **kwargs)
 |      The following kwarg properties are supported
 |
 |      Properties:
 |          agg_filter: a filter function, which takes a (m, n, 3) float array and a dpi value, and returns a (m, n, 3) array
 |          alpha: float or None
 |          animated: bool
 |          antialiased or aa: unknown
 |          capstyle: {'butt', 'round', 'projecting'}
 |          clip_box: `.Bbox`
 |          clip_on: bool
 |          clip_path: Patch or (Path, Transform) or None
 |          color: color
 |          contains: unknown
 |          edgecolor or ec: color or None or 'auto'
 |          facecolor or fc: color or None
 |          figure: `.Figure`
 |          fill: bool
 |          gid: str
 |          hatch: {'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
 |          in_layout: bool
 |          joinstyle: {'miter', 'round', 'bevel'}
 |          label: object
 |          linestyle or ls: {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
 |          linewidth or lw: float or None
 |          path_effects: `.AbstractPathEffect`
 |          picker: None or bool or callable
 |          rasterized: bool or None
 |          sketch_params: (scale: float, length: float, randomness: float)
 |          snap: bool or None
 |          transform: `.Transform`
 |          url: str
 |          visible: bool
 |          zorder: float
 |
 |  contains(self, mouseevent, radius=None)
 |      Test whether the mouse event occurred in the patch.
 |
 |      Returns
 |      -------
 |      (bool, empty dict)
 |
 |  contains_point(self, point, radius=None)
 |      Return whether the given point is inside the patch.
 |
 |      Parameters
 |      ----------
 |      point : (float, float)
 |          The point (x, y) to check, in target coordinates of
 |          ``self.get_transform()``. These are display coordinates for patches
 |          that are added to a figure or axes.
 |      radius : float, optional
 |          Add an additional margin on the patch in target coordinates of
 |          ``self.get_transform()``. See `.Path.contains_point` for further
 |          details.
 |
 |      Returns
 |      -------
 |      bool
 |
 |      Notes
 |      -----
 |      The proper use of this method depends on the transform of the patch.
 |      Isolated patches do not have a transform. In this case, the patch
 |      creation coordinates and the point coordinates match. The following
 |      example checks that the center of a circle is within the circle
 |
 |      >>> center = 0, 0
 |      >>> c = Circle(center, radius=1)
 |      >>> c.contains_point(center)
 |      True
 |
 |      The convention of checking against the transformed patch stems from
 |      the fact that this method is predominantly used to check if display
 |      coordinates (e.g. from mouse events) are within the patch. If you want
 |      to do the above check with data coordinates, you have to properly
 |      transform them first:
 |
 |      >>> center = 0, 0
 |      >>> c = Circle(center, radius=1)
 |      >>> plt.gca().add_patch(c)
 |      >>> transformed_center = c.get_transform().transform(center)
 |      >>> c.contains_point(transformed_center)
 |      True
 |
 |  contains_points(self, points, radius=None)
 |      Return whether the given points are inside the patch.
 |
 |      Parameters
 |      ----------
 |      points : (N, 2) array
 |          The points to check, in target coordinates of
 |          ``self.get_transform()``. These are display coordinates for patches
 |          that are added to a figure or axes. Columns contain x and y values.
 |      radius : float, optional
 |          Add an additional margin on the patch in target coordinates of
 |          ``self.get_transform()``. See `.Path.contains_point` for further
 |          details.
 |
 |      Returns
 |      -------
 |      length-N bool array
 |
 |      Notes
 |      -----
 |      The proper use of this method depends on the transform of the patch.
 |      See the notes on `.Patch.contains_point`.
 |
 |  draw(self, renderer)
 |      Draw the Artist (and its children) using the given renderer.
 |
 |      This has no effect if the artist is not visible (`.Artist.get_visible`
 |      returns False).
 |
 |      Parameters
 |      ----------
 |      renderer : `.RendererBase` subclass.
 |
 |      Notes
 |      -----
 |      This method is overridden in the Artist subclasses.
 |
 |  get_aa(self)
 |      Alias for `get_antialiased`.
 |
 |  get_antialiased(self)
 |      Return whether antialiasing is used for drawing.
 |
 |  get_capstyle(self)
 |      Return the capstyle.
 |
 |  get_data_transform(self)
 |      Return the `~.transforms.Transform` mapping data coordinates to
 |      physical coordinates.
 |
 |  get_ec(self)
 |      Alias for `get_edgecolor`.
 |
 |  get_edgecolor(self)
 |      Return the edge color.
 |
 |  get_extents(self)
 |      Return the `Patch`'s axis-aligned extents as a `~.transforms.Bbox`.
 |
 |  get_facecolor(self)
 |      Return the face color.
 |
 |  get_fc(self)
 |      Alias for `get_facecolor`.
 |
 |  get_fill(self)
 |      Return whether the patch is filled.
 |
 |  get_hatch(self)
 |      Return the hatching pattern.
 |
 |  get_joinstyle(self)
 |      Return the joinstyle.
 |
 |  get_linestyle(self)
 |      Return the linestyle.
 |
 |  get_linewidth(self)
 |      Return the line width in points.
 |
 |  get_ls(self)
 |      Alias for `get_linestyle`.
 |
 |  get_lw(self)
 |      Alias for `get_linewidth`.
 |
 |  get_patch_transform(self)
 |      Return the `~.transforms.Transform` instance mapping patch coordinates
 |      to data coordinates.
 |
 |      For example, one may define a patch of a circle which represents a
 |      radius of 5 by providing coordinates for a unit circle, and a
 |      transform which scales the coordinates (the patch coordinate) by 5.
 |
 |  get_path(self)
 |      Return the path of this patch.
 |
 |  get_transform(self)
 |      Return the `~.transforms.Transform` applied to the `Patch`.
 |
 |  get_verts(self)
 |      Return a copy of the vertices used in this patch.
 |
 |      If the patch contains Bezier curves, the curves will be interpolated by
 |      line segments.  To access the curves as curves, use `get_path`.
 |
 |  get_window_extent(self, renderer=None)
 |      Get the axes bounding box in display space.
 |
 |      The bounding box' width and height are nonnegative.
 |
 |      Subclasses should override for inclusion in the bounding box
 |      "tight" calculation. Default is to return an empty bounding
 |      box at 0, 0.
 |
 |      Be careful when using this function, the results will not update
 |      if the artist window extent of the artist changes.  The extent
 |      can change due to any changes in the transform stack, such as
 |      changing the axes limits, the figure size, or the canvas used
 |      (as is done when saving a figure).  This can lead to unexpected
 |      behavior where interactive figures will look fine on the screen,
 |      but will save incorrectly.
 |
 |  set_aa(self, aa)
 |      Alias for `set_antialiased`.
 |
 |  set_alpha(self, alpha)
 |      Set the alpha value used for blending - not supported on all backends.
 |
 |      Parameters
 |      ----------
 |      alpha : float or None
 |
 |  set_antialiased(self, aa)
 |      Set whether to use antialiased rendering.
 |
 |      Parameters
 |      ----------
 |      b : bool or None
 |
 |  set_capstyle(self, s)
 |      Set the capstyle.
 |
 |      Parameters
 |      ----------
 |      s : {'butt', 'round', 'projecting'}
 |
 |  set_color(self, c)
 |      Set both the edgecolor and the facecolor.
 |
 |      Parameters
 |      ----------
 |      c : color
 |
 |      See Also
 |      --------
 |      Patch.set_facecolor, Patch.set_edgecolor
 |          For setting the edge or face color individually.
 |
 |  set_ec(self, color)
 |      Alias for `set_edgecolor`.
 |
 |  set_edgecolor(self, color)
 |      Set the patch edge color.
 |
 |      Parameters
 |      ----------
 |      color : color or None or 'auto'
 |
 |  set_facecolor(self, color)
 |      Set the patch face color.
 |
 |      Parameters
 |      ----------
 |      color : color or None
 |
 |  set_fc(self, color)
 |      Alias for `set_facecolor`.
 |
 |  set_fill(self, b)
 |      Set whether to fill the patch.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_hatch(self, hatch)
 |      Set the hatching pattern.
 |
 |      *hatch* can be one of::
 |
 |        /   - diagonal hatching
 |        \   - back diagonal
 |        |   - vertical
 |        -   - horizontal
 |        +   - crossed
 |        x   - crossed diagonal
 |        o   - small circle
 |        O   - large circle
 |        .   - dots
 |        *   - stars
 |
 |      Letters can be combined, in which case all the specified
 |      hatchings are done.  If same letter repeats, it increases the
 |      density of hatching of that pattern.
 |
 |      Hatching is supported in the PostScript, PDF, SVG and Agg
 |      backends only.
 |
 |      Parameters
 |      ----------
 |      hatch : {'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
 |
 |  set_joinstyle(self, s)
 |      Set the joinstyle.
 |
 |      Parameters
 |      ----------
 |      s : {'miter', 'round', 'bevel'}
 |
 |  set_linestyle(self, ls)
 |      Set the patch linestyle.
 |
 |      ===========================   =================
 |      linestyle                     description
 |      ===========================   =================
 |      ``'-'`` or ``'solid'``        solid line
 |      ``'--'`` or  ``'dashed'``     dashed line
 |      ``'-.'`` or  ``'dashdot'``    dash-dotted line
 |      ``':'`` or ``'dotted'``       dotted line
 |      ===========================   =================
 |
 |      Alternatively a dash tuple of the following form can be provided::
 |
 |          (offset, onoffseq)
 |
 |      where ``onoffseq`` is an even length tuple of on and off ink in points.
 |
 |      Parameters
 |      ----------
 |      ls : {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
 |          The line style.
 |
 |  set_linewidth(self, w)
 |      Set the patch linewidth in points.
 |
 |      Parameters
 |      ----------
 |      w : float or None
 |
 |  set_ls(self, ls)
 |      Alias for `set_linestyle`.
 |
 |  set_lw(self, w)
 |      Alias for `set_linewidth`.
 |
 |  update_from(self, other)
 |      Copy properties from *other* to *self*.
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |
 |  fill
 |      Return whether the patch is filled.
 |
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |
 |  validCap = ('butt', 'round', 'projecting')
 |
 |  validJoin = ('miter', 'round', 'bevel')
 |
 |  zorder = 1
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from matplotlib.artist.Artist:
 |
 |  __getstate__(self)
 |
 |  add_callback(self, func)
 |      Add a callback function that will be called whenever one of the
 |      `.Artist`'s properties changes.
 |
 |      Parameters
 |      ----------
 |      func : callable
 |          The callback function. It must have the signature::
 |
 |              def func(artist: Artist) -> Any
 |
 |          where *artist* is the calling `.Artist`. Return values may exist
 |          but are ignored.
 |
 |      Returns
 |      -------
 |      int
 |          The observer id associated with the callback. This id can be
 |          used for removing the callback with `.remove_callback` later.
 |
 |      See Also
 |      --------
 |      remove_callback
 |
 |  convert_xunits(self, x)
 |      Convert *x* using the unit type of the xaxis.
 |
 |      If the artist is not in contained in an Axes or if the xaxis does not
 |      have units, *x* itself is returned.
 |
 |  convert_yunits(self, y)
 |      Convert *y* using the unit type of the yaxis.
 |
 |      If the artist is not in contained in an Axes or if the yaxis does not
 |      have units, *y* itself is returned.
 |
 |  findobj(self, match=None, include_self=True)
 |      Find artist objects.
 |
 |      Recursively find all `.Artist` instances contained in the artist.
 |
 |      Parameters
 |      ----------
 |      match
 |          A filter criterion for the matches. This can be
 |
 |          - *None*: Return all objects contained in artist.
 |          - A function with signature ``def match(artist: Artist) -> bool``.
 |            The result will only contain artists for which the function
 |            returns *True*.
 |          - A class instance: e.g., `.Line2D`. The result will only contain
 |            artists of this class or its subclasses (``isinstance`` check).
 |
 |      include_self : bool
 |          Include *self* in the list to be checked for a match.
 |
 |      Returns
 |      -------
 |      list of `.Artist`
 |
 |  format_cursor_data(self, data)
 |      Return a string representation of *data*.
 |
 |      .. note::
 |          This method is intended to be overridden by artist subclasses.
 |          As an end-user of Matplotlib you will most likely not call this
 |          method yourself.
 |
 |      The default implementation converts ints and floats and arrays of ints
 |      and floats into a comma-separated string enclosed in square brackets.
 |
 |      See Also
 |      --------
 |      get_cursor_data
 |
 |  get_agg_filter(self)
 |      Return filter function to be used for agg filter.
 |
 |  get_alpha(self)
 |      Return the alpha value used for blending - not supported on all
 |      backends.
 |
 |  get_animated(self)
 |      Return whether the artist is animated.
 |
 |  get_children(self)
 |      Return a list of the child `.Artist`\s of this `.Artist`.
 |
 |  get_clip_box(self)
 |      Return the clipbox.
 |
 |  get_clip_on(self)
 |      Return whether the artist uses clipping.
 |
 |  get_clip_path(self)
 |      Return the clip path.
 |
 |  get_contains(self)
 |      [*Deprecated*] Return the custom contains function of the artist if set, or *None*.
 |
 |      See Also
 |      --------
 |      set_contains
 |
 |      Notes
 |      -----
 |      .. deprecated:: 3.3
 |
 |  get_cursor_data(self, event)
 |      Return the cursor data for a given event.
 |
 |      .. note::
 |          This method is intended to be overridden by artist subclasses.
 |          As an end-user of Matplotlib you will most likely not call this
 |          method yourself.
 |
 |      Cursor data can be used by Artists to provide additional context
 |      information for a given event. The default implementation just returns
 |      *None*.
 |
 |      Subclasses can override the method and return arbitrary data. However,
 |      when doing so, they must ensure that `.format_cursor_data` can convert
 |      the data to a string representation.
 |
 |      The only current use case is displaying the z-value of an `.AxesImage`
 |      in the status bar of a plot window, while moving the mouse.
 |
 |      Parameters
 |      ----------
 |      event : `matplotlib.backend_bases.MouseEvent`
 |
 |      See Also
 |      --------
 |      format_cursor_data
 |
 |  get_figure(self)
 |      Return the `.Figure` instance the artist belongs to.
 |
 |  get_gid(self)
 |      Return the group id.
 |
 |  get_in_layout(self)
 |      Return boolean flag, ``True`` if artist is included in layout
 |      calculations.
 |
 |      E.g. :doc:`/tutorials/intermediate/constrainedlayout_guide`,
 |      `.Figure.tight_layout()`, and
 |      ``fig.savefig(fname, bbox_inches='tight')``.
 |
 |  get_label(self)
 |      Return the label used for this artist in the legend.
 |
 |  get_path_effects(self)
 |
 |  get_picker(self)
 |      Return the picking behavior of the artist.
 |
 |      The possible values are described in `.set_picker`.
 |
 |      See Also
 |      --------
 |      set_picker, pickable, pick
 |
 |  get_rasterized(self)
 |      Return whether the artist is to be rasterized.
 |
 |  get_sketch_params(self)
 |      Return the sketch parameters for the artist.
 |
 |      Returns
 |      -------
 |      tuple or None
 |
 |          A 3-tuple with the following elements:
 |
 |          - *scale*: The amplitude of the wiggle perpendicular to the
 |            source line.
 |          - *length*: The length of the wiggle along the line.
 |          - *randomness*: The scale factor by which the length is
 |            shrunken or expanded.
 |
 |          Returns *None* if no sketch parameters were set.
 |
 |  get_snap(self)
 |      Return the snap setting.
 |
 |      See `.set_snap` for details.
 |
 |  get_tightbbox(self, renderer)
 |      Like `.Artist.get_window_extent`, but includes any clipping.
 |
 |      Parameters
 |      ----------
 |      renderer : `.RendererBase` subclass
 |          renderer that will be used to draw the figures (i.e.
 |          ``fig.canvas.get_renderer()``)
 |
 |      Returns
 |      -------
 |      `.Bbox`
 |          The enclosing bounding box (in figure pixel coordinates).
 |
 |  get_transformed_clip_path_and_affine(self)
 |      Return the clip path with the non-affine part of its
 |      transformation applied, and the remaining affine part of its
 |      transformation.
 |
 |  get_url(self)
 |      Return the url.
 |
 |  get_visible(self)
 |      Return the visibility.
 |
 |  get_zorder(self)
 |      Return the artist's zorder.
 |
 |  have_units(self)
 |      Return *True* if units are set on any axis.
 |
 |  is_transform_set(self)
 |      Return whether the Artist has an explicitly set transform.
 |
 |      This is *True* after `.set_transform` has been called.
 |
 |  pchanged(self)
 |      Call all of the registered callbacks.
 |
 |      This function is triggered internally when a property is changed.
 |
 |      See Also
 |      --------
 |      add_callback
 |      remove_callback
 |
 |  pick(self, mouseevent)
 |      Process a pick event.
 |
 |      Each child artist will fire a pick event if *mouseevent* is over
 |      the artist and the artist has picker set.
 |
 |      See Also
 |      --------
 |      set_picker, get_picker, pickable
 |
 |  pickable(self)
 |      Return whether the artist is pickable.
 |
 |      See Also
 |      --------
 |      set_picker, get_picker, pick
 |
 |  properties(self)
 |      Return a dictionary of all the properties of the artist.
 |
 |  remove(self)
 |      Remove the artist from the figure if possible.
 |
 |      The effect will not be visible until the figure is redrawn, e.g.,
 |      with `.FigureCanvasBase.draw_idle`.  Call `~.axes.Axes.relim` to
 |      update the axes limits if desired.
 |
 |      Note: `~.axes.Axes.relim` will not see collections even if the
 |      collection was added to the axes with *autolim* = True.
 |
 |      Note: there is no support for removing the artist's legend entry.
 |
 |  remove_callback(self, oid)
 |      Remove a callback based on its observer id.
 |
 |      See Also
 |      --------
 |      add_callback
 |
 |  set(self, **kwargs)
 |      A property batch setter.  Pass *kwargs* to set properties.
 |
 |  set_agg_filter(self, filter_func)
 |      Set the agg filter.
 |
 |      Parameters
 |      ----------
 |      filter_func : callable
 |          A filter function, which takes a (m, n, 3) float array and a dpi
 |          value, and returns a (m, n, 3) array.
 |
 |          .. ACCEPTS: a filter function, which takes a (m, n, 3) float array
 |              and a dpi value, and returns a (m, n, 3) array
 |
 |  set_animated(self, b)
 |      Set the artist's animation state.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_clip_box(self, clipbox)
 |      Set the artist's clip `.Bbox`.
 |
 |      Parameters
 |      ----------
 |      clipbox : `.Bbox`
 |
 |  set_clip_on(self, b)
 |      Set whether the artist uses clipping.
 |
 |      When False artists will be visible outside of the axes which
 |      can lead to unexpected results.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_clip_path(self, path, transform=None)
 |      Set the artist's clip path.
 |
 |      Parameters
 |      ----------
 |      path : `.Patch` or `.Path` or `.TransformedPath` or None
 |          The clip path. If given a `.Path`, *transform* must be provided as
 |          well. If *None*, a previously set clip path is removed.
 |      transform : `~matplotlib.transforms.Transform`, optional
 |          Only used if *path* is a `.Path`, in which case the given `.Path`
 |          is converted to a `.TransformedPath` using *transform*.
 |
 |      Notes
 |      -----
 |      For efficiency, if *path* is a `.Rectangle` this method will set the
 |      clipping box to the corresponding rectangle and set the clipping path
 |      to ``None``.
 |
 |      For technical reasons (support of `~.Artist.set`), a tuple
 |      (*path*, *transform*) is also accepted as a single positional
 |      parameter.
 |
 |      .. ACCEPTS: Patch or (Path, Transform) or None
 |
 |  set_contains(self, picker)
 |      [*Deprecated*] Define a custom contains syntax for the artist.
 |
 |      The provided callable replaces the default `.contains` method
 |      of the artist.
 |
 |      Parameters
 |      ----------
 |      picker : callable
 |          A custom picker function to evaluate if an event is within the
 |          artist. The function must have the signature::
 |
 |              def contains(artist: Artist, event: MouseEvent) -> bool, dict
 |
 |          that returns:
 |
 |          - a bool indicating if the event is within the artist
 |          - a dict of additional information. The dict should at least
 |            return the same information as the default ``contains()``
 |            implementation of the respective artist, but may provide
 |            additional information.
 |
 |      Notes
 |      -----
 |      .. deprecated:: 3.3
 |
 |  set_figure(self, fig)
 |      Set the `.Figure` instance the artist belongs to.
 |
 |      Parameters
 |      ----------
 |      fig : `.Figure`
 |
 |  set_gid(self, gid)
 |      Set the (group) id for the artist.
 |
 |      Parameters
 |      ----------
 |      gid : str
 |
 |  set_in_layout(self, in_layout)
 |      Set if artist is to be included in layout calculations,
 |      E.g. :doc:`/tutorials/intermediate/constrainedlayout_guide`,
 |      `.Figure.tight_layout()`, and
 |      ``fig.savefig(fname, bbox_inches='tight')``.
 |
 |      Parameters
 |      ----------
 |      in_layout : bool
 |
 |  set_label(self, s)
 |      Set a label that will be displayed in the legend.
 |
 |      Parameters
 |      ----------
 |      s : object
 |          *s* will be converted to a string by calling `str`.
 |
 |  set_path_effects(self, path_effects)
 |      Set the path effects.
 |
 |      Parameters
 |      ----------
 |      path_effects : `.AbstractPathEffect`
 |
 |  set_picker(self, picker)
 |      Define the picking behavior of the artist.
 |
 |      Parameters
 |      ----------
 |      picker : None or bool or callable
 |          This can be one of the following:
 |
 |          - *None*: Picking is disabled for this artist (default).
 |
 |          - A boolean: If *True* then picking will be enabled and the
 |            artist will fire a pick event if the mouse event is over
 |            the artist.
 |
 |          - A function: If picker is callable, it is a user supplied
 |            function which determines whether the artist is hit by the
 |            mouse event::
 |
 |              hit, props = picker(artist, mouseevent)
 |
 |            to determine the hit syntax.  if the mouse event is over the
 |            artist, return *hit=True* and props is a dictionary of
 |            properties you want added to the PickEvent attributes.
 |
 |          - *deprecated*: For `.Line2D` only, *picker* can also be a float
 |            that sets the tolerance for checking whether an event occurred
 |            "on" the line; this is deprecated.  Use `.Line2D.set_pickradius`
 |            instead.
 |
 |  set_rasterized(self, rasterized)
 |      Force rasterized (bitmap) drawing in vector backend output.
 |
 |      Defaults to None, which implies the backend's default behavior.
 |
 |      Parameters
 |      ----------
 |      rasterized : bool or None
 |
 |  set_sketch_params(self, scale=None, length=None, randomness=None)
 |      Sets the sketch parameters.
 |
 |      Parameters
 |      ----------
 |      scale : float, optional
 |          The amplitude of the wiggle perpendicular to the source
 |          line, in pixels.  If scale is `None`, or not provided, no
 |          sketch filter will be provided.
 |      length : float, optional
 |           The length of the wiggle along the line, in pixels
 |           (default 128.0)
 |      randomness : float, optional
 |          The scale factor by which the length is shrunken or
 |          expanded (default 16.0)
 |
 |          .. ACCEPTS: (scale: float, length: float, randomness: float)
 |
 |  set_snap(self, snap)
 |      Set the snapping behavior.
 |
 |      Snapping aligns positions with the pixel grid, which results in
 |      clearer images. For example, if a black line of 1px width was
 |      defined at a position in between two pixels, the resulting image
 |      would contain the interpolated value of that line in the pixel grid,
 |      which would be a grey value on both adjacent pixel positions. In
 |      contrast, snapping will move the line to the nearest integer pixel
 |      value, so that the resulting image will really contain a 1px wide
 |      black line.
 |
 |      Snapping is currently only supported by the Agg and MacOSX backends.
 |
 |      Parameters
 |      ----------
 |      snap : bool or None
 |          Possible values:
 |
 |          - *True*: Snap vertices to the nearest pixel center.
 |          - *False*: Do not modify vertex positions.
 |          - *None*: (auto) If the path contains only rectilinear line
 |            segments, round to the nearest pixel center.
 |
 |  set_transform(self, t)
 |      Set the artist transform.
 |
 |      Parameters
 |      ----------
 |      t : `.Transform`
 |
 |  set_url(self, url)
 |      Set the url for the artist.
 |
 |      Parameters
 |      ----------
 |      url : str
 |
 |  set_visible(self, b)
 |      Set the artist's visibility.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_zorder(self, level)
 |      Set the zorder for the artist.  Artists with lower zorder
 |      values are drawn first.
 |
 |      Parameters
 |      ----------
 |      level : float
 |
 |  update(self, props)
 |      Update this artist's properties from the dict *props*.
 |
 |      Parameters
 |      ----------
 |      props : dict
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from matplotlib.artist.Artist:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)
 |
 |  axes
 |      The `~.axes.Axes` instance the artist resides in, or *None*.
 |
 |  mouseover
 |      If this property is set to *True*, the artist will be queried for
 |      custom context information when the mouse cursor moves over it.
 |
 |      See also :meth:`get_cursor_data`, :class:`.ToolCursorPosition` and
 |      :class:`.NavigationToolbar2`.
 |
 |  stale
 |      Whether the artist is 'stale' and needs to be re-drawn for the output
 |      to match the internal state of the artist.
 |
 |  sticky_edges
 |      ``x`` and ``y`` sticky edge lists for autoscaling.
 |
 |      When performing autoscaling, if a data limit coincides with a value in
 |      the corresponding sticky_edges list, then no margin will be added--the
 |      view limit "sticks" to the edge. A typical use case is histograms,
 |      where one usually expects no margin on the bottom edge (0) of the
 |      histogram.
 |
 |      This attribute cannot be assigned to; however, the ``x`` and ``y``
 |      lists can be modified in place as needed.
 |
 |      Examples
 |      --------
 |      >>> artist.sticky_edges.x[:] = (xmin, xmax)
 |      >>> artist.sticky_edges.y[:] = (ymin, ymax)
    """

    import matplotlib.patches as patches
    # from matplotlib.collections import PatchCollection
    # import matplotlib.lines as mlines

    @staticmethod
    def arc():
        """
class Arc(Ellipse)
 |  Arc(xy, width, height, angle=0.0, theta1=0.0, theta2=360.0, **kwargs)
 |
 |  An elliptical arc, i.e. a segment of an ellipse.
 |
 |  Due to internal optimizations, there are certain restrictions on using Arc:
 |
 |  - The arc cannot be filled.
 |
 |  - The arc must be used in an `~.axes.Axes` instance. It can not be added
 |    directly to a `.Figure` because it is optimized to only render the
 |    segments that are inside the axes bounding box with high resolution.
 |
 |  Method resolution order:
 |      Arc
 |      Ellipse
 |      Patch
 |      matplotlib.artist.Artist
 |      builtins.object
 |
 |  Methods defined here:
 |
 |  __init__(self, xy, width, height, angle=0.0, theta1=0.0, theta2=360.0, **kwargs)
 |      Parameters
 |      ----------
 |      xy : (float, float)
 |          The center of the ellipse.
 |
 |      width : float
 |          The length of the horizontal axis.
 |
 |      height : float
 |          The length of the vertical axis.
 |
 |      angle : float
 |          Rotation of the ellipse in degrees (counterclockwise).
 |
 |      theta1, theta2 : float, default: 0, 360
 |          Starting and ending angles of the arc in degrees. These values
 |          are relative to *angle*, e.g. if *angle* = 45 and *theta1* = 90
 |          the absolute starting angle is 135.
 |          Default *theta1* = 0, *theta2* = 360, i.e. a complete ellipse.
 |          The arc is drawn in the counterclockwise direction.
 |          Angles greater than or equal to 360, or smaller than 0, are
 |          represented by an equivalent angle in the range [0, 360), by
 |          taking the input value mod 360.
 |
 |      Other Parameters
 |      ----------------
 |      **kwargs : `.Patch` properties
 |          Most `.Patch` properties are supported as keyword arguments,
 |          with the exception of *fill* and *facecolor* because filling is
 |          not supported.
 |
 |      Properties:
 |          agg_filter: a filter function, which takes a (m, n, 3) float array and a dpi value, and returns a (m, n, 3) array
 |          alpha: float or None
 |          animated: bool
 |          antialiased or aa: unknown
 |          capstyle: {'butt', 'round', 'projecting'}
 |          clip_box: `.Bbox`
 |          clip_on: bool
 |          clip_path: Patch or (Path, Transform) or None
 |          color: color
 |          contains: unknown
 |          edgecolor or ec: color or None or 'auto'
 |          facecolor or fc: color or None
 |          figure: `.Figure`
 |          fill: bool
 |          gid: str
 |          hatch: {'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
 |          in_layout: bool
 |          joinstyle: {'miter', 'round', 'bevel'}
 |          label: object
 |          linestyle or ls: {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
 |          linewidth or lw: float or None
 |          path_effects: `.AbstractPathEffect`
 |          picker: None or bool or callable
 |          rasterized: bool or None
 |          sketch_params: (scale: float, length: float, randomness: float)
 |          snap: bool or None
 |          transform: `.Transform`
 |          url: str
 |          visible: bool
 |          zorder: float
 |
 |  __str__(self)
 |      Return str(self).
 |
 |  draw(self, renderer)
 |      Draw the arc to the given *renderer*.
 |
 |      Notes
 |      -----
 |      Ellipses are normally drawn using an approximation that uses
 |      eight cubic Bezier splines.  The error of this approximation
 |      is 1.89818e-6, according to this unverified source:
 |
 |        Lancaster, Don.  *Approximating a Circle or an Ellipse Using
 |        Four Bezier Cubic Splines.*
 |
 |        https://www.tinaja.com/glib/ellipse4.pdf
 |
 |      There is a use case where very large ellipses must be drawn
 |      with very high accuracy, and it is too expensive to render the
 |      entire ellipse with enough segments (either splines or line
 |      segments).  Therefore, in the case where either radius of the
 |      ellipse is large enough that the error of the spline
 |      approximation will be visible (greater than one pixel offset
 |      from the ideal), a different technique is used.
 |
 |      In that case, only the visible parts of the ellipse are drawn,
 |      with each visible arc using a fixed number of spline segments
 |      (8).  The algorithm proceeds as follows:
 |
 |      1. The points where the ellipse intersects the axes bounding
 |         box are located.  (This is done be performing an inverse
 |         transformation on the axes bbox such that it is relative
 |         to the unit circle -- this makes the intersection
 |         calculation much easier than doing rotated ellipse
 |         intersection directly).
 |
 |         This uses the "line intersecting a circle" algorithm from:
 |
 |             Vince, John.  *Geometry for Computer Graphics: Formulae,
 |             Examples & Proofs.*  London: Springer-Verlag, 2005.
 |
 |      2. The angles of each of the intersection points are calculated.
 |
 |      3. Proceeding counterclockwise starting in the positive
 |         x-direction, each of the visible arc-segments between the
 |         pairs of vertices are drawn using the Bezier arc
 |         approximation technique implemented in `.Path.arc`.
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from Ellipse:
 |
 |  get_angle(self)
 |      Return the angle of the ellipse.
 |
 |  get_center(self)
 |      Return the center of the ellipse.
 |
 |  get_height(self)
 |      Return the height of the ellipse.
 |
 |  get_patch_transform(self)
 |      Return the `~.transforms.Transform` instance mapping patch coordinates
 |      to data coordinates.
 |
 |      For example, one may define a patch of a circle which represents a
 |      radius of 5 by providing coordinates for a unit circle, and a
 |      transform which scales the coordinates (the patch coordinate) by 5.
 |
 |  get_path(self)
 |      Return the path of the ellipse.
 |
 |  get_width(self)
 |      Return the width of the ellipse.
 |
 |  set_angle(self, angle)
 |      Set the angle of the ellipse.
 |
 |      Parameters
 |      ----------
 |      angle : float
 |
 |  set_center(self, xy)
 |      Set the center of the ellipse.
 |
 |      Parameters
 |      ----------
 |      xy : (float, float)
 |
 |  set_height(self, height)
 |      Set the height of the ellipse.
 |
 |      Parameters
 |      ----------
 |      height : float
 |
 |  set_width(self, width)
 |      Set the width of the ellipse.
 |
 |      Parameters
 |      ----------
 |      width : float
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from Ellipse:
 |
 |  angle
 |      Return the angle of the ellipse.
 |
 |  center
 |      Return the center of the ellipse.
 |
 |  height
 |      Return the height of the ellipse.
 |
 |  width
 |      Return the width of the ellipse.
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from Patch:
 |
 |  contains(self, mouseevent, radius=None)
 |      Test whether the mouse event occurred in the patch.
 |
 |      Returns
 |      -------
 |      (bool, empty dict)
 |
 |  contains_point(self, point, radius=None)
 |      Return whether the given point is inside the patch.
 |
 |      Parameters
 |      ----------
 |      point : (float, float)
 |          The point (x, y) to check, in target coordinates of
 |          ``self.get_transform()``. These are display coordinates for patches
 |          that are added to a figure or axes.
 |      radius : float, optional
 |          Add an additional margin on the patch in target coordinates of
 |          ``self.get_transform()``. See `.Path.contains_point` for further
 |          details.
 |
 |      Returns
 |      -------
 |      bool
 |
 |      Notes
 |      -----
 |      The proper use of this method depends on the transform of the patch.
 |      Isolated patches do not have a transform. In this case, the patch
 |      creation coordinates and the point coordinates match. The following
 |      example checks that the center of a circle is within the circle
 |
 |      >>> center = 0, 0
 |      >>> c = Circle(center, radius=1)
 |      >>> c.contains_point(center)
 |      True
 |
 |      The convention of checking against the transformed patch stems from
 |      the fact that this method is predominantly used to check if display
 |      coordinates (e.g. from mouse events) are within the patch. If you want
 |      to do the above check with data coordinates, you have to properly
 |      transform them first:
 |
 |      >>> center = 0, 0
 |      >>> c = Circle(center, radius=1)
 |      >>> plt.gca().add_patch(c)
 |      >>> transformed_center = c.get_transform().transform(center)
 |      >>> c.contains_point(transformed_center)
 |      True
 |
 |  contains_points(self, points, radius=None)
 |      Return whether the given points are inside the patch.
 |
 |      Parameters
 |      ----------
 |      points : (N, 2) array
 |          The points to check, in target coordinates of
 |          ``self.get_transform()``. These are display coordinates for patches
 |          that are added to a figure or axes. Columns contain x and y values.
 |      radius : float, optional
 |          Add an additional margin on the patch in target coordinates of
 |          ``self.get_transform()``. See `.Path.contains_point` for further
 |          details.
 |
 |      Returns
 |      -------
 |      length-N bool array
 |
 |      Notes
 |      -----
 |      The proper use of this method depends on the transform of the patch.
 |      See the notes on `.Patch.contains_point`.
 |
 |  get_aa(self)
 |      Alias for `get_antialiased`.
 |
 |  get_antialiased(self)
 |      Return whether antialiasing is used for drawing.
 |
 |  get_capstyle(self)
 |      Return the capstyle.
 |
 |  get_data_transform(self)
 |      Return the `~.transforms.Transform` mapping data coordinates to
 |      physical coordinates.
 |
 |  get_ec(self)
 |      Alias for `get_edgecolor`.
 |
 |  get_edgecolor(self)
 |      Return the edge color.
 |
 |  get_extents(self)
 |      Return the `Patch`'s axis-aligned extents as a `~.transforms.Bbox`.
 |
 |  get_facecolor(self)
 |      Return the face color.
 |
 |  get_fc(self)
 |      Alias for `get_facecolor`.
 |
 |  get_fill(self)
 |      Return whether the patch is filled.
 |
 |  get_hatch(self)
 |      Return the hatching pattern.
 |
 |  get_joinstyle(self)
 |      Return the joinstyle.
 |
 |  get_linestyle(self)
 |      Return the linestyle.
 |
 |  get_linewidth(self)
 |      Return the line width in points.
 |
 |  get_ls(self)
 |      Alias for `get_linestyle`.
 |
 |  get_lw(self)
 |      Alias for `get_linewidth`.
 |
 |  get_transform(self)
 |      Return the `~.transforms.Transform` applied to the `Patch`.
 |
 |  get_verts(self)
 |      Return a copy of the vertices used in this patch.
 |
 |      If the patch contains Bezier curves, the curves will be interpolated by
 |      line segments.  To access the curves as curves, use `get_path`.
 |
 |  get_window_extent(self, renderer=None)
 |      Get the axes bounding box in display space.
 |
 |      The bounding box' width and height are nonnegative.
 |
 |      Subclasses should override for inclusion in the bounding box
 |      "tight" calculation. Default is to return an empty bounding
 |      box at 0, 0.
 |
 |      Be careful when using this function, the results will not update
 |      if the artist window extent of the artist changes.  The extent
 |      can change due to any changes in the transform stack, such as
 |      changing the axes limits, the figure size, or the canvas used
 |      (as is done when saving a figure).  This can lead to unexpected
 |      behavior where interactive figures will look fine on the screen,
 |      but will save incorrectly.
 |
 |  set_aa(self, aa)
 |      Alias for `set_antialiased`.
 |
 |  set_alpha(self, alpha)
 |      Set the alpha value used for blending - not supported on all backends.
 |
 |      Parameters
 |      ----------
 |      alpha : float or None
 |
 |  set_antialiased(self, aa)
 |      Set whether to use antialiased rendering.
 |
 |      Parameters
 |      ----------
 |      b : bool or None
 |
 |  set_capstyle(self, s)
 |      Set the capstyle.
 |
 |      Parameters
 |      ----------
 |      s : {'butt', 'round', 'projecting'}
 |
 |  set_color(self, c)
 |      Set both the edgecolor and the facecolor.
 |
 |      Parameters
 |      ----------
 |      c : color
 |
 |      See Also
 |      --------
 |      Patch.set_facecolor, Patch.set_edgecolor
 |          For setting the edge or face color individually.
 |
 |  set_ec(self, color)
 |      Alias for `set_edgecolor`.
 |
 |  set_edgecolor(self, color)
 |      Set the patch edge color.
 |
 |      Parameters
 |      ----------
 |      color : color or None or 'auto'
 |
 |  set_facecolor(self, color)
 |      Set the patch face color.
 |
 |      Parameters
 |      ----------
 |      color : color or None
 |
 |  set_fc(self, color)
 |      Alias for `set_facecolor`.
 |
 |  set_fill(self, b)
 |      Set whether to fill the patch.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_hatch(self, hatch)
 |      Set the hatching pattern.
 |
 |      *hatch* can be one of::
 |
 |        /   - diagonal hatching
 |        \   - back diagonal
 |        |   - vertical
 |        -   - horizontal
 |        +   - crossed
 |        x   - crossed diagonal
 |        o   - small circle
 |        O   - large circle
 |        .   - dots
 |        *   - stars
 |
 |      Letters can be combined, in which case all the specified
 |      hatchings are done.  If same letter repeats, it increases the
 |      density of hatching of that pattern.
 |
 |      Hatching is supported in the PostScript, PDF, SVG and Agg
 |      backends only.
 |
 |      Parameters
 |      ----------
 |      hatch : {'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
 |
 |  set_joinstyle(self, s)
 |      Set the joinstyle.
 |
 |      Parameters
 |      ----------
 |      s : {'miter', 'round', 'bevel'}
 |
 |  set_linestyle(self, ls)
 |      Set the patch linestyle.
 |
 |      ===========================   =================
 |      linestyle                     description
 |      ===========================   =================
 |      ``'-'`` or ``'solid'``        solid line
 |      ``'--'`` or  ``'dashed'``     dashed line
 |      ``'-.'`` or  ``'dashdot'``    dash-dotted line
 |      ``':'`` or ``'dotted'``       dotted line
 |      ===========================   =================
 |
 |      Alternatively a dash tuple of the following form can be provided::
 |
 |          (offset, onoffseq)
 |
 |      where ``onoffseq`` is an even length tuple of on and off ink in points.
 |
 |      Parameters
 |      ----------
 |      ls : {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
 |          The line style.
 |
 |  set_linewidth(self, w)
 |      Set the patch linewidth in points.
 |
 |      Parameters
 |      ----------
 |      w : float or None
 |
 |  set_ls(self, ls)
 |      Alias for `set_linestyle`.
 |
 |  set_lw(self, w)
 |      Alias for `set_linewidth`.
 |
 |  update_from(self, other)
 |      Copy properties from *other* to *self*.
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from Patch:
 |
 |  fill
 |      Return whether the patch is filled.
 |
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from Patch:
 |
 |  validCap = ('butt', 'round', 'projecting')
 |
 |  validJoin = ('miter', 'round', 'bevel')
 |
 |  zorder = 1
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from matplotlib.artist.Artist:
 |
 |  __getstate__(self)
 |
 |  add_callback(self, func)
 |      Add a callback function that will be called whenever one of the
 |      `.Artist`'s properties changes.
 |
 |      Parameters
 |      ----------
 |      func : callable
 |          The callback function. It must have the signature::
 |
 |              def func(artist: Artist) -> Any
 |
 |          where *artist* is the calling `.Artist`. Return values may exist
 |          but are ignored.
 |
 |      Returns
 |      -------
 |      int
 |          The observer id associated with the callback. This id can be
 |          used for removing the callback with `.remove_callback` later.
 |
 |      See Also
 |      --------
 |      remove_callback
 |
 |  convert_xunits(self, x)
 |      Convert *x* using the unit type of the xaxis.
 |
 |      If the artist is not in contained in an Axes or if the xaxis does not
 |      have units, *x* itself is returned.
 |
 |  convert_yunits(self, y)
 |      Convert *y* using the unit type of the yaxis.
 |
 |      If the artist is not in contained in an Axes or if the yaxis does not
 |      have units, *y* itself is returned.
 |
 |  findobj(self, match=None, include_self=True)
 |      Find artist objects.
 |
 |      Recursively find all `.Artist` instances contained in the artist.
 |
 |      Parameters
 |      ----------
 |      match
 |          A filter criterion for the matches. This can be
 |
 |          - *None*: Return all objects contained in artist.
 |          - A function with signature ``def match(artist: Artist) -> bool``.
 |            The result will only contain artists for which the function
 |            returns *True*.
 |          - A class instance: e.g., `.Line2D`. The result will only contain
 |            artists of this class or its subclasses (``isinstance`` check).
 |
 |      include_self : bool
 |          Include *self* in the list to be checked for a match.
 |
 |      Returns
 |      -------
 |      list of `.Artist`
 |
 |  format_cursor_data(self, data)
 |      Return a string representation of *data*.
 |
 |      .. note::
 |          This method is intended to be overridden by artist subclasses.
 |          As an end-user of Matplotlib you will most likely not call this
 |          method yourself.
 |
 |      The default implementation converts ints and floats and arrays of ints
 |      and floats into a comma-separated string enclosed in square brackets.
 |
 |      See Also
 |      --------
 |      get_cursor_data
 |
 |  get_agg_filter(self)
 |      Return filter function to be used for agg filter.
 |
 |  get_alpha(self)
 |      Return the alpha value used for blending - not supported on all
 |      backends.
 |
 |  get_animated(self)
 |      Return whether the artist is animated.
 |
 |  get_children(self)
 |      Return a list of the child `.Artist`\s of this `.Artist`.
 |
 |  get_clip_box(self)
 |      Return the clipbox.
 |
 |  get_clip_on(self)
 |      Return whether the artist uses clipping.
 |
 |  get_clip_path(self)
 |      Return the clip path.
 |
 |  get_contains(self)
 |      [*Deprecated*] Return the custom contains function of the artist if set, or *None*.
 |
 |      See Also
 |      --------
 |      set_contains
 |
 |      Notes
 |      -----
 |      .. deprecated:: 3.3
 |
 |  get_cursor_data(self, event)
 |      Return the cursor data for a given event.
 |
 |      .. note::
 |          This method is intended to be overridden by artist subclasses.
 |          As an end-user of Matplotlib you will most likely not call this
 |          method yourself.
 |
 |      Cursor data can be used by Artists to provide additional context
 |      information for a given event. The default implementation just returns
 |      *None*.
 |
 |      Subclasses can override the method and return arbitrary data. However,
 |      when doing so, they must ensure that `.format_cursor_data` can convert
 |      the data to a string representation.
 |
 |      The only current use case is displaying the z-value of an `.AxesImage`
 |      in the status bar of a plot window, while moving the mouse.
 |
 |      Parameters
 |      ----------
 |      event : `matplotlib.backend_bases.MouseEvent`
 |
 |      See Also
 |      --------
 |      format_cursor_data
 |
 |  get_figure(self)
 |      Return the `.Figure` instance the artist belongs to.
 |
 |  get_gid(self)
 |      Return the group id.
 |
 |  get_in_layout(self)
 |      Return boolean flag, ``True`` if artist is included in layout
 |      calculations.
 |
 |      E.g. :doc:`/tutorials/intermediate/constrainedlayout_guide`,
 |      `.Figure.tight_layout()`, and
 |      ``fig.savefig(fname, bbox_inches='tight')``.
 |
 |  get_label(self)
 |      Return the label used for this artist in the legend.
 |
 |  get_path_effects(self)
 |
 |  get_picker(self)
 |      Return the picking behavior of the artist.
 |
 |      The possible values are described in `.set_picker`.
 |
 |      See Also
 |      --------
 |      set_picker, pickable, pick
 |
 |  get_rasterized(self)
 |      Return whether the artist is to be rasterized.
 |
 |  get_sketch_params(self)
 |      Return the sketch parameters for the artist.
 |
 |      Returns
 |      -------
 |      tuple or None
 |
 |          A 3-tuple with the following elements:
 |
 |          - *scale*: The amplitude of the wiggle perpendicular to the
 |            source line.
 |          - *length*: The length of the wiggle along the line.
 |          - *randomness*: The scale factor by which the length is
 |            shrunken or expanded.
 |
 |          Returns *None* if no sketch parameters were set.
 |
 |  get_snap(self)
 |      Return the snap setting.
 |
 |      See `.set_snap` for details.
 |
 |  get_tightbbox(self, renderer)
 |      Like `.Artist.get_window_extent`, but includes any clipping.
 |
 |      Parameters
 |      ----------
 |      renderer : `.RendererBase` subclass
 |          renderer that will be used to draw the figures (i.e.
 |          ``fig.canvas.get_renderer()``)
 |
 |      Returns
 |      -------
 |      `.Bbox`
 |          The enclosing bounding box (in figure pixel coordinates).
 |
 |  get_transformed_clip_path_and_affine(self)
 |      Return the clip path with the non-affine part of its
 |      transformation applied, and the remaining affine part of its
 |      transformation.
 |
 |  get_url(self)
 |      Return the url.
 |
 |  get_visible(self)
 |      Return the visibility.
 |
 |  get_zorder(self)
 |      Return the artist's zorder.
 |
 |  have_units(self)
 |      Return *True* if units are set on any axis.
 |
 |  is_transform_set(self)
 |      Return whether the Artist has an explicitly set transform.
 |
 |      This is *True* after `.set_transform` has been called.
 |
 |  pchanged(self)
 |      Call all of the registered callbacks.
 |
 |      This function is triggered internally when a property is changed.
 |
 |      See Also
 |      --------
 |      add_callback
 |      remove_callback
 |
 |  pick(self, mouseevent)
 |      Process a pick event.
 |
 |      Each child artist will fire a pick event if *mouseevent* is over
 |      the artist and the artist has picker set.
 |
 |      See Also
 |      --------
 |      set_picker, get_picker, pickable
 |
 |  pickable(self)
 |      Return whether the artist is pickable.
 |
 |      See Also
 |      --------
 |      set_picker, get_picker, pick
 |
 |  properties(self)
 |      Return a dictionary of all the properties of the artist.
 |
 |  remove(self)
 |      Remove the artist from the figure if possible.
 |
 |      The effect will not be visible until the figure is redrawn, e.g.,
 |      with `.FigureCanvasBase.draw_idle`.  Call `~.axes.Axes.relim` to
 |      update the axes limits if desired.
 |
 |      Note: `~.axes.Axes.relim` will not see collections even if the
 |      collection was added to the axes with *autolim* = True.
 |
 |      Note: there is no support for removing the artist's legend entry.
 |
 |  remove_callback(self, oid)
 |      Remove a callback based on its observer id.
 |
 |      See Also
 |      --------
 |      add_callback
 |
 |  set(self, **kwargs)
 |      A property batch setter.  Pass *kwargs* to set properties.
 |
 |  set_agg_filter(self, filter_func)
 |      Set the agg filter.
 |
 |      Parameters
 |      ----------
 |      filter_func : callable
 |          A filter function, which takes a (m, n, 3) float array and a dpi
 |          value, and returns a (m, n, 3) array.
 |
 |          .. ACCEPTS: a filter function, which takes a (m, n, 3) float array
 |              and a dpi value, and returns a (m, n, 3) array
 |
 |  set_animated(self, b)
 |      Set the artist's animation state.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_clip_box(self, clipbox)
 |      Set the artist's clip `.Bbox`.
 |
 |      Parameters
 |      ----------
 |      clipbox : `.Bbox`
 |
 |  set_clip_on(self, b)
 |      Set whether the artist uses clipping.
 |
 |      When False artists will be visible outside of the axes which
 |      can lead to unexpected results.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_clip_path(self, path, transform=None)
 |      Set the artist's clip path.
 |
 |      Parameters
 |      ----------
 |      path : `.Patch` or `.Path` or `.TransformedPath` or None
 |          The clip path. If given a `.Path`, *transform* must be provided as
 |          well. If *None*, a previously set clip path is removed.
 |      transform : `~matplotlib.transforms.Transform`, optional
 |          Only used if *path* is a `.Path`, in which case the given `.Path`
 |          is converted to a `.TransformedPath` using *transform*.
 |
 |      Notes
 |      -----
 |      For efficiency, if *path* is a `.Rectangle` this method will set the
 |      clipping box to the corresponding rectangle and set the clipping path
 |      to ``None``.
 |
 |      For technical reasons (support of `~.Artist.set`), a tuple
 |      (*path*, *transform*) is also accepted as a single positional
 |      parameter.
 |
 |      .. ACCEPTS: Patch or (Path, Transform) or None
 |
 |  set_contains(self, picker)
 |      [*Deprecated*] Define a custom contains syntax for the artist.
 |
 |      The provided callable replaces the default `.contains` method
 |      of the artist.
 |
 |      Parameters
 |      ----------
 |      picker : callable
 |          A custom picker function to evaluate if an event is within the
 |          artist. The function must have the signature::
 |
 |              def contains(artist: Artist, event: MouseEvent) -> bool, dict
 |
 |          that returns:
 |
 |          - a bool indicating if the event is within the artist
 |          - a dict of additional information. The dict should at least
 |            return the same information as the default ``contains()``
 |            implementation of the respective artist, but may provide
 |            additional information.
 |
 |      Notes
 |      -----
 |      .. deprecated:: 3.3
 |
 |  set_figure(self, fig)
 |      Set the `.Figure` instance the artist belongs to.
 |
 |      Parameters
 |      ----------
 |      fig : `.Figure`
 |
 |  set_gid(self, gid)
 |      Set the (group) id for the artist.
 |
 |      Parameters
 |      ----------
 |      gid : str
 |
 |  set_in_layout(self, in_layout)
 |      Set if artist is to be included in layout calculations,
 |      E.g. :doc:`/tutorials/intermediate/constrainedlayout_guide`,
 |      `.Figure.tight_layout()`, and
 |      ``fig.savefig(fname, bbox_inches='tight')``.
 |
 |      Parameters
 |      ----------
 |      in_layout : bool
 |
 |  set_label(self, s)
 |      Set a label that will be displayed in the legend.
 |
 |      Parameters
 |      ----------
 |      s : object
 |          *s* will be converted to a string by calling `str`.
 |
 |  set_path_effects(self, path_effects)
 |      Set the path effects.
 |
 |      Parameters
 |      ----------
 |      path_effects : `.AbstractPathEffect`
 |
 |  set_picker(self, picker)
 |      Define the picking behavior of the artist.
 |
 |      Parameters
 |      ----------
 |      picker : None or bool or callable
 |          This can be one of the following:
 |
 |          - *None*: Picking is disabled for this artist (default).
 |
 |          - A boolean: If *True* then picking will be enabled and the
 |            artist will fire a pick event if the mouse event is over
 |            the artist.
 |
 |          - A function: If picker is callable, it is a user supplied
 |            function which determines whether the artist is hit by the
 |            mouse event::
 |
 |              hit, props = picker(artist, mouseevent)
 |
 |            to determine the hit syntax.  if the mouse event is over the
 |            artist, return *hit=True* and props is a dictionary of
 |            properties you want added to the PickEvent attributes.
 |
 |          - *deprecated*: For `.Line2D` only, *picker* can also be a float
 |            that sets the tolerance for checking whether an event occurred
 |            "on" the line; this is deprecated.  Use `.Line2D.set_pickradius`
 |            instead.
 |
 |  set_rasterized(self, rasterized)
 |      Force rasterized (bitmap) drawing in vector backend output.
 |
 |      Defaults to None, which implies the backend's default behavior.
 |
 |      Parameters
 |      ----------
 |      rasterized : bool or None
 |
 |  set_sketch_params(self, scale=None, length=None, randomness=None)
 |      Sets the sketch parameters.
 |
 |      Parameters
 |      ----------
 |      scale : float, optional
 |          The amplitude of the wiggle perpendicular to the source
 |          line, in pixels.  If scale is `None`, or not provided, no
 |          sketch filter will be provided.
 |      length : float, optional
 |           The length of the wiggle along the line, in pixels
 |           (default 128.0)
 |      randomness : float, optional
 |          The scale factor by which the length is shrunken or
 |          expanded (default 16.0)
 |
 |          .. ACCEPTS: (scale: float, length: float, randomness: float)
 |
 |  set_snap(self, snap)
 |      Set the snapping behavior.
 |
 |      Snapping aligns positions with the pixel grid, which results in
 |      clearer images. For example, if a black line of 1px width was
 |      defined at a position in between two pixels, the resulting image
 |      would contain the interpolated value of that line in the pixel grid,
 |      which would be a grey value on both adjacent pixel positions. In
 |      contrast, snapping will move the line to the nearest integer pixel
 |      value, so that the resulting image will really contain a 1px wide
 |      black line.
 |
 |      Snapping is currently only supported by the Agg and MacOSX backends.
 |
 |      Parameters
 |      ----------
 |      snap : bool or None
 |          Possible values:
 |
 |          - *True*: Snap vertices to the nearest pixel center.
 |          - *False*: Do not modify vertex positions.
 |          - *None*: (auto) If the path contains only rectilinear line
 |            segments, round to the nearest pixel center.
 |
 |  set_transform(self, t)
 |      Set the artist transform.
 |
 |      Parameters
 |      ----------
 |      t : `.Transform`
 |
 |  set_url(self, url)
 |      Set the url for the artist.
 |
 |      Parameters
 |      ----------
 |      url : str
 |
 |  set_visible(self, b)
 |      Set the artist's visibility.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_zorder(self, level)
 |      Set the zorder for the artist.  Artists with lower zorder
 |      values are drawn first.
 |
 |      Parameters
 |      ----------
 |      level : float
 |
 |  update(self, props)
 |      Update this artist's properties from the dict *props*.
 |
 |      Parameters
 |      ----------
 |      props : dict
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from matplotlib.artist.Artist:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)
 |
 |  axes
 |      The `~.axes.Axes` instance the artist resides in, or *None*.
 |
 |  mouseover
 |      If this property is set to *True*, the artist will be queried for
 |      custom context information when the mouse cursor moves over it.
 |
 |      See also :meth:`get_cursor_data`, :class:`.ToolCursorPosition` and
 |      :class:`.NavigationToolbar2`.
 |
 |  stale
 |      Whether the artist is 'stale' and needs to be re-drawn for the output
 |      to match the internal state of the artist.
 |
 |  sticky_edges
 |      ``x`` and ``y`` sticky edge lists for autoscaling.
 |
 |      When performing autoscaling, if a data limit coincides with a value in
 |      the corresponding sticky_edges list, then no margin will be added--the
 |      view limit "sticks" to the edge. A typical use case is histograms,
 |      where one usually expects no margin on the bottom edge (0) of the
 |      histogram.
 |
 |      This attribute cannot be assigned to; however, the ``x`` and ``y``
 |      lists can be modified in place as needed.
 |
 |      Examples
 |      --------
 |      >>> artist.sticky_edges.x[:] = (xmin, xmax)
 |      >>> artist.sticky_edges.y[:] = (ymin, ymax)
        """

        # create figure, axes
        fig, ax = plt.subplots()

        # create arc and add to axes
        xy, w, h, a, t1, t2 = (0.5, 0.1), 0.80, 0.6, 0, 20, 180
        arc = DemoPatch.patches.Arc(xy=xy, width=w, height=h, angle=a, theta1=t1, theta2=t2, color='b', linewidth=3)
        ax.add_patch(arc)

        # draw lines of angles
        x1 = [xy[0], xy[0]+w/2]
        y1 = [xy[1], xy[1]]
        # line from center to start point of arc
        r = w*h / np.sqrt(w**2 * np.sin(t1/360*np.pi*2)**2 + h**2 * np.cos(t1/360*np.pi*2)**2) / 2
        x2 = [xy[0], xy[0]+r*np.cos(t1/360*np.pi*2)]
        y2 = [xy[1], xy[1]+r*np.sin(t1/360*np.pi*2)]
        # line from center to end point of arc
        x3 = [xy[0], xy[0]-w/2]
        y3 = [xy[1], xy[1]]
        ax.plot(x1, y1, 'r--', x2, y2, 'r--', x3, y3, 'r--')

        # show theta1, theta2 with wedges
        wedge1 = DemoPatch.patches.Wedge(xy, 0.1, 0, t1, alpha=0.45, color='y')
        ax.add_patch(wedge1)
        wedge2 = DemoPatch.patches.Wedge(xy, 0.05, 0, t2, alpha=0.55, color='g')
        ax.add_patch(wedge2)

        # annotate theta1, theta2
        ax.annotate(text=f'theta1={t1}'+r'$^{\circ}$',
                    xytext=(0.75, 0.5),
                    xy=(xy[0]+0.1, xy[1]+0.01),
                    arrowprops=dict(arrowstyle='fancy', alpha=0.3),
                    bbox=dict(color='purple', alpha=0.3)
                    )
        ax.annotate(text=f'theta2={t2}'+r'$^{\circ}$',
                    xytext=(0.25, 0.5),
                    xy=(xy[0]-0.02, xy[1]+0.05),
                    arrowprops=dict(width=0.5, alpha=0.3),
                    bbox=dict(color='purple', alpha=0.3)
                    )

        # draw point and text center of arc
        ax.scatter(xy[0], xy[1], c='r', s=50)
        ax.text(xy[0] - 0.05, xy[1] - 0.02, f'xy:{xy}', va='top', bbox=dict(pad=0, alpha=0.1))

        # set axes
        ax.set(xlim=(0, 1), ylim=(0, 0.6), aspect=1)


    @staticmethod
    def rectangle():
        """
class Rectangle(Patch)
 |  Rectangle(xy, width, height, angle=0.0, **kwargs)
 |
 |  A rectangle defined via an anchor point *xy* and its *width* and *height*.
 |
 |  The rectangle extends from ``xy[0]`` to ``xy[0] + width`` in x-direction
 |  and from ``xy[1]`` to ``xy[1] + height`` in y-direction. ::
 |
 |    :                +------------------+
 |    :                |                  |
 |    :              height               |
 |    :                |                  |
 |    :               (xy)---- width -----+
 |
 |  One may picture *xy* as the bottom left corner, but which corner *xy* is
 |  actually depends on the the direction of the axis and the sign of *width*
 |  and *height*; e.g. *xy* would be the bottom right corner if the x-axis
 |  was inverted or if *width* was negative.
 |
 |  Method resolution order:
 |      Rectangle
 |      Patch
 |      matplotlib.artist.Artist
 |      builtins.object
 |
 |  Methods defined here:
 |
 |  __init__(self, xy, width, height, angle=0.0, **kwargs)
 |      Parameters
 |      ----------
 |      xy : (float, float)
 |          The anchor point.
 |      width : float
 |          Rectangle width.
 |      height : float
 |          Rectangle height.
 |      angle : float, default: 0
 |          Rotation in degrees anti-clockwise about *xy*.
 |
 |      Other Parameters
 |      ----------------
 |      **kwargs : `.Patch` properties
 |          Properties:
 |          agg_filter: a filter function, which takes a (m, n, 3) float array and a dpi value, and returns a (m, n, 3) array
 |          alpha: float or None
 |          animated: bool
 |          antialiased or aa: unknown
 |          capstyle: {'butt', 'round', 'projecting'}
 |          clip_box: `.Bbox`
 |          clip_on: bool
 |          clip_path: Patch or (Path, Transform) or None
 |          color: color
 |          contains: unknown
 |          edgecolor or ec: color or None or 'auto'
 |          facecolor or fc: color or None
 |          figure: `.Figure`
 |          fill: bool
 |          gid: str
 |          hatch: {'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
 |          in_layout: bool
 |          joinstyle: {'miter', 'round', 'bevel'}
 |          label: object
 |          linestyle or ls: {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
 |          linewidth or lw: float or None
 |          path_effects: `.AbstractPathEffect`
 |          picker: None or bool or callable
 |          rasterized: bool or None
 |          sketch_params: (scale: float, length: float, randomness: float)
 |          snap: bool or None
 |          transform: `.Transform`
 |          url: str
 |          visible: bool
 |          zorder: float
 |
 |  __str__(self)
 |      Return str(self).
 |
 |  get_bbox(self)
 |      Return the `.Bbox`.
 |
 |  get_height(self)
 |      Return the height of the rectangle.
 |
 |  get_patch_transform(self)
 |      Return the `~.transforms.Transform` instance mapping patch coordinates
 |      to data coordinates.
 |
 |      For example, one may define a patch of a circle which represents a
 |      radius of 5 by providing coordinates for a unit circle, and a
 |      transform which scales the coordinates (the patch coordinate) by 5.
 |
 |  get_path(self)
 |      Return the vertices of the rectangle.
 |
 |  get_width(self)
 |      Return the width of the rectangle.
 |
 |  get_x(self)
 |      Return the left coordinate of the rectangle.
 |
 |  get_xy(self)
 |      Return the left and bottom coords of the rectangle as a tuple.
 |
 |  get_y(self)
 |      Return the bottom coordinate of the rectangle.
 |
 |  set_bounds(self, *args)
 |      Set the bounds of the rectangle as *left*, *bottom*, *width*, *height*.
 |
 |      The values may be passed as separate parameters or as a tuple::
 |
 |          set_bounds(left, bottom, width, height)
 |          set_bounds((left, bottom, width, height))
 |
 |      .. ACCEPTS: (left, bottom, width, height)
 |
 |  set_height(self, h)
 |      Set the height of the rectangle.
 |
 |  set_width(self, w)
 |      Set the width of the rectangle.
 |
 |  set_x(self, x)
 |      Set the left coordinate of the rectangle.
 |
 |  set_xy(self, xy)
 |      Set the left and bottom coordinates of the rectangle.
 |
 |      Parameters
 |      ----------
 |      xy : (float, float)
 |
 |  set_y(self, y)
 |      Set the bottom coordinate of the rectangle.
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |
 |  xy
 |      Return the left and bottom coords of the rectangle as a tuple.
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from Patch:
 |
 |  contains(self, mouseevent, radius=None)
 |      Test whether the mouse event occurred in the patch.
 |
 |      Returns
 |      -------
 |      (bool, empty dict)
 |
 |  contains_point(self, point, radius=None)
 |      Return whether the given point is inside the patch.
 |
 |      Parameters
 |      ----------
 |      point : (float, float)
 |          The point (x, y) to check, in target coordinates of
 |          ``self.get_transform()``. These are display coordinates for patches
 |          that are added to a figure or axes.
 |      radius : float, optional
 |          Add an additional margin on the patch in target coordinates of
 |          ``self.get_transform()``. See `.Path.contains_point` for further
 |          details.
 |
 |      Returns
 |      -------
 |      bool
 |
 |      Notes
 |      -----
 |      The proper use of this method depends on the transform of the patch.
 |      Isolated patches do not have a transform. In this case, the patch
 |      creation coordinates and the point coordinates match. The following
 |      example checks that the center of a circle is within the circle
 |
 |      >>> center = 0, 0
 |      >>> c = Circle(center, radius=1)
 |      >>> c.contains_point(center)
 |      True
 |
 |      The convention of checking against the transformed patch stems from
 |      the fact that this method is predominantly used to check if display
 |      coordinates (e.g. from mouse events) are within the patch. If you want
 |      to do the above check with data coordinates, you have to properly
 |      transform them first:
 |
 |      >>> center = 0, 0
 |      >>> c = Circle(center, radius=1)
 |      >>> plt.gca().add_patch(c)
 |      >>> transformed_center = c.get_transform().transform(center)
 |      >>> c.contains_point(transformed_center)
 |      True
 |
 |  contains_points(self, points, radius=None)
 |      Return whether the given points are inside the patch.
 |
 |      Parameters
 |      ----------
 |      points : (N, 2) array
 |          The points to check, in target coordinates of
 |          ``self.get_transform()``. These are display coordinates for patches
 |          that are added to a figure or axes. Columns contain x and y values.
 |      radius : float, optional
 |          Add an additional margin on the patch in target coordinates of
 |          ``self.get_transform()``. See `.Path.contains_point` for further
 |          details.
 |
 |      Returns
 |      -------
 |      length-N bool array
 |
 |      Notes
 |      -----
 |      The proper use of this method depends on the transform of the patch.
 |      See the notes on `.Patch.contains_point`.
 |
 |  draw(self, renderer)
 |      Draw the Artist (and its children) using the given renderer.
 |
 |      This has no effect if the artist is not visible (`.Artist.get_visible`
 |      returns False).
 |
 |      Parameters
 |      ----------
 |      renderer : `.RendererBase` subclass.
 |
 |      Notes
 |      -----
 |      This method is overridden in the Artist subclasses.
 |
 |  get_aa(self)
 |      Alias for `get_antialiased`.
 |
 |  get_antialiased(self)
 |      Return whether antialiasing is used for drawing.
 |
 |  get_capstyle(self)
 |      Return the capstyle.
 |
 |  get_data_transform(self)
 |      Return the `~.transforms.Transform` mapping data coordinates to
 |      physical coordinates.
 |
 |  get_ec(self)
 |      Alias for `get_edgecolor`.
 |
 |  get_edgecolor(self)
 |      Return the edge color.
 |
 |  get_extents(self)
 |      Return the `Patch`'s axis-aligned extents as a `~.transforms.Bbox`.
 |
 |  get_facecolor(self)
 |      Return the face color.
 |
 |  get_fc(self)
 |      Alias for `get_facecolor`.
 |
 |  get_fill(self)
 |      Return whether the patch is filled.
 |
 |  get_hatch(self)
 |      Return the hatching pattern.
 |
 |  get_joinstyle(self)
 |      Return the joinstyle.
 |
 |  get_linestyle(self)
 |      Return the linestyle.
 |
 |  get_linewidth(self)
 |      Return the line width in points.
 |
 |  get_ls(self)
 |      Alias for `get_linestyle`.
 |
 |  get_lw(self)
 |      Alias for `get_linewidth`.
 |
 |  get_transform(self)
 |      Return the `~.transforms.Transform` applied to the `Patch`.
 |
 |  get_verts(self)
 |      Return a copy of the vertices used in this patch.
 |
 |      If the patch contains Bezier curves, the curves will be interpolated by
 |      line segments.  To access the curves as curves, use `get_path`.
 |
 |  get_window_extent(self, renderer=None)
 |      Get the axes bounding box in display space.
 |
 |      The bounding box' width and height are nonnegative.
 |
 |      Subclasses should override for inclusion in the bounding box
 |      "tight" calculation. Default is to return an empty bounding
 |      box at 0, 0.
 |
 |      Be careful when using this function, the results will not update
 |      if the artist window extent of the artist changes.  The extent
 |      can change due to any changes in the transform stack, such as
 |      changing the axes limits, the figure size, or the canvas used
 |      (as is done when saving a figure).  This can lead to unexpected
 |      behavior where interactive figures will look fine on the screen,
 |      but will save incorrectly.
 |
 |  set_aa(self, aa)
 |      Alias for `set_antialiased`.
 |
 |  set_alpha(self, alpha)
 |      Set the alpha value used for blending - not supported on all backends.
 |
 |      Parameters
 |      ----------
 |      alpha : float or None
 |
 |  set_antialiased(self, aa)
 |      Set whether to use antialiased rendering.
 |
 |      Parameters
 |      ----------
 |      b : bool or None
 |
 |  set_capstyle(self, s)
 |      Set the capstyle.
 |
 |      Parameters
 |      ----------
 |      s : {'butt', 'round', 'projecting'}
 |
 |  set_color(self, c)
 |      Set both the edgecolor and the facecolor.
 |
 |      Parameters
 |      ----------
 |      c : color
 |
 |      See Also
 |      --------
 |      Patch.set_facecolor, Patch.set_edgecolor
 |          For setting the edge or face color individually.
 |
 |  set_ec(self, color)
 |      Alias for `set_edgecolor`.
 |
 |  set_edgecolor(self, color)
 |      Set the patch edge color.
 |
 |      Parameters
 |      ----------
 |      color : color or None or 'auto'
 |
 |  set_facecolor(self, color)
 |      Set the patch face color.
 |
 |      Parameters
 |      ----------
 |      color : color or None
 |
 |  set_fc(self, color)
 |      Alias for `set_facecolor`.
 |
 |  set_fill(self, b)
 |      Set whether to fill the patch.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_hatch(self, hatch)
 |      Set the hatching pattern.
 |
 |      *hatch* can be one of::
 |
 |        /   - diagonal hatching
 |        \   - back diagonal
 |        |   - vertical
 |        -   - horizontal
 |        +   - crossed
 |        x   - crossed diagonal
 |        o   - small circle
 |        O   - large circle
 |        .   - dots
 |        *   - stars
 |
 |      Letters can be combined, in which case all the specified
 |      hatchings are done.  If same letter repeats, it increases the
 |      density of hatching of that pattern.
 |
 |      Hatching is supported in the PostScript, PDF, SVG and Agg
 |      backends only.
 |
 |      Parameters
 |      ----------
 |      hatch : {'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
 |
 |  set_joinstyle(self, s)
 |      Set the joinstyle.
 |
 |      Parameters
 |      ----------
 |      s : {'miter', 'round', 'bevel'}
 |
 |  set_linestyle(self, ls)
 |      Set the patch linestyle.
 |
 |      ===========================   =================
 |      linestyle                     description
 |      ===========================   =================
 |      ``'-'`` or ``'solid'``        solid line
 |      ``'--'`` or  ``'dashed'``     dashed line
 |      ``'-.'`` or  ``'dashdot'``    dash-dotted line
 |      ``':'`` or ``'dotted'``       dotted line
 |      ===========================   =================
 |
 |      Alternatively a dash tuple of the following form can be provided::
 |
 |          (offset, onoffseq)
 |
 |      where ``onoffseq`` is an even length tuple of on and off ink in points.
 |
 |      Parameters
 |      ----------
 |      ls : {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
 |          The line style.
 |
 |  set_linewidth(self, w)
 |      Set the patch linewidth in points.
 |
 |      Parameters
 |      ----------
 |      w : float or None
 |
 |  set_ls(self, ls)
 |      Alias for `set_linestyle`.
 |
 |  set_lw(self, w)
 |      Alias for `set_linewidth`.
 |
 |  update_from(self, other)
 |      Copy properties from *other* to *self*.
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from Patch:
 |
 |  fill
 |      Return whether the patch is filled.
 |
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from Patch:
 |
 |  validCap = ('butt', 'round', 'projecting')
 |
 |  validJoin = ('miter', 'round', 'bevel')
 |
 |  zorder = 1
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from matplotlib.artist.Artist:
 |
 |  __getstate__(self)
 |
 |  add_callback(self, func)
 |      Add a callback function that will be called whenever one of the
 |      `.Artist`'s properties changes.
 |
 |      Parameters
 |      ----------
 |      func : callable
 |          The callback function. It must have the signature::
 |
 |              def func(artist: Artist) -> Any
 |
 |          where *artist* is the calling `.Artist`. Return values may exist
 |          but are ignored.
 |
 |      Returns
 |      -------
 |      int
 |          The observer id associated with the callback. This id can be
 |          used for removing the callback with `.remove_callback` later.
 |
 |      See Also
 |      --------
 |      remove_callback
 |
 |  convert_xunits(self, x)
 |      Convert *x* using the unit type of the xaxis.
 |
 |      If the artist is not in contained in an Axes or if the xaxis does not
 |      have units, *x* itself is returned.
 |
 |  convert_yunits(self, y)
 |      Convert *y* using the unit type of the yaxis.
 |
 |      If the artist is not in contained in an Axes or if the yaxis does not
 |      have units, *y* itself is returned.
 |
 |  findobj(self, match=None, include_self=True)
 |      Find artist objects.
 |
 |      Recursively find all `.Artist` instances contained in the artist.
 |
 |      Parameters
 |      ----------
 |      match
 |          A filter criterion for the matches. This can be
 |
 |          - *None*: Return all objects contained in artist.
 |          - A function with signature ``def match(artist: Artist) -> bool``.
 |            The result will only contain artists for which the function
 |            returns *True*.
 |          - A class instance: e.g., `.Line2D`. The result will only contain
 |            artists of this class or its subclasses (``isinstance`` check).
 |
 |      include_self : bool
 |          Include *self* in the list to be checked for a match.
 |
 |      Returns
 |      -------
 |      list of `.Artist`
 |
 |  format_cursor_data(self, data)
 |      Return a string representation of *data*.
 |
 |      .. note::
 |          This method is intended to be overridden by artist subclasses.
 |          As an end-user of Matplotlib you will most likely not call this
 |          method yourself.
 |
 |      The default implementation converts ints and floats and arrays of ints
 |      and floats into a comma-separated string enclosed in square brackets.
 |
 |      See Also
 |      --------
 |      get_cursor_data
 |
 |  get_agg_filter(self)
 |      Return filter function to be used for agg filter.
 |
 |  get_alpha(self)
 |      Return the alpha value used for blending - not supported on all
 |      backends.
 |
 |  get_animated(self)
 |      Return whether the artist is animated.
 |
 |  get_children(self)
 |      Return a list of the child `.Artist`\s of this `.Artist`.
 |
 |  get_clip_box(self)
 |      Return the clipbox.
 |
 |  get_clip_on(self)
 |      Return whether the artist uses clipping.
 |
 |  get_clip_path(self)
 |      Return the clip path.
 |
 |  get_contains(self)
 |      [*Deprecated*] Return the custom contains function of the artist if set, or *None*.
 |
 |      See Also
 |      --------
 |      set_contains
 |
 |      Notes
 |      -----
 |      .. deprecated:: 3.3
 |
 |  get_cursor_data(self, event)
 |      Return the cursor data for a given event.
 |
 |      .. note::
 |          This method is intended to be overridden by artist subclasses.
 |          As an end-user of Matplotlib you will most likely not call this
 |          method yourself.
 |
 |      Cursor data can be used by Artists to provide additional context
 |      information for a given event. The default implementation just returns
 |      *None*.
 |
 |      Subclasses can override the method and return arbitrary data. However,
 |      when doing so, they must ensure that `.format_cursor_data` can convert
 |      the data to a string representation.
 |
 |      The only current use case is displaying the z-value of an `.AxesImage`
 |      in the status bar of a plot window, while moving the mouse.
 |
 |      Parameters
 |      ----------
 |      event : `matplotlib.backend_bases.MouseEvent`
 |
 |      See Also
 |      --------
 |      format_cursor_data
 |
 |  get_figure(self)
 |      Return the `.Figure` instance the artist belongs to.
 |
 |  get_gid(self)
 |      Return the group id.
 |
 |  get_in_layout(self)
 |      Return boolean flag, ``True`` if artist is included in layout
 |      calculations.
 |
 |      E.g. :doc:`/tutorials/intermediate/constrainedlayout_guide`,
 |      `.Figure.tight_layout()`, and
 |      ``fig.savefig(fname, bbox_inches='tight')``.
 |
 |  get_label(self)
 |      Return the label used for this artist in the legend.
 |
 |  get_path_effects(self)
 |
 |  get_picker(self)
 |      Return the picking behavior of the artist.
 |
 |      The possible values are described in `.set_picker`.
 |
 |      See Also
 |      --------
 |      set_picker, pickable, pick
 |
 |  get_rasterized(self)
 |      Return whether the artist is to be rasterized.
 |
 |  get_sketch_params(self)
 |      Return the sketch parameters for the artist.
 |
 |      Returns
 |      -------
 |      tuple or None
 |
 |          A 3-tuple with the following elements:
 |
 |          - *scale*: The amplitude of the wiggle perpendicular to the
 |            source line.
 |          - *length*: The length of the wiggle along the line.
 |          - *randomness*: The scale factor by which the length is
 |            shrunken or expanded.
 |
 |          Returns *None* if no sketch parameters were set.
 |
 |  get_snap(self)
 |      Return the snap setting.
 |
 |      See `.set_snap` for details.
 |
 |  get_tightbbox(self, renderer)
 |      Like `.Artist.get_window_extent`, but includes any clipping.
 |
 |      Parameters
 |      ----------
 |      renderer : `.RendererBase` subclass
 |          renderer that will be used to draw the figures (i.e.
 |          ``fig.canvas.get_renderer()``)
 |
 |      Returns
 |      -------
 |      `.Bbox`
 |          The enclosing bounding box (in figure pixel coordinates).
 |
 |  get_transformed_clip_path_and_affine(self)
 |      Return the clip path with the non-affine part of its
 |      transformation applied, and the remaining affine part of its
 |      transformation.
 |
 |  get_url(self)
 |      Return the url.
 |
 |  get_visible(self)
 |      Return the visibility.
 |
 |  get_zorder(self)
 |      Return the artist's zorder.
 |
 |  have_units(self)
 |      Return *True* if units are set on any axis.
 |
 |  is_transform_set(self)
 |      Return whether the Artist has an explicitly set transform.
 |
 |      This is *True* after `.set_transform` has been called.
 |
 |  pchanged(self)
 |      Call all of the registered callbacks.
 |
 |      This function is triggered internally when a property is changed.
 |
 |      See Also
 |      --------
 |      add_callback
 |      remove_callback
 |
 |  pick(self, mouseevent)
 |      Process a pick event.
 |
 |      Each child artist will fire a pick event if *mouseevent* is over
 |      the artist and the artist has picker set.
 |
 |      See Also
 |      --------
 |      set_picker, get_picker, pickable
 |
 |  pickable(self)
 |      Return whether the artist is pickable.
 |
 |      See Also
 |      --------
 |      set_picker, get_picker, pick
 |
 |  properties(self)
 |      Return a dictionary of all the properties of the artist.
 |
 |  remove(self)
 |      Remove the artist from the figure if possible.
 |
 |      The effect will not be visible until the figure is redrawn, e.g.,
 |      with `.FigureCanvasBase.draw_idle`.  Call `~.axes.Axes.relim` to
 |      update the axes limits if desired.
 |
 |      Note: `~.axes.Axes.relim` will not see collections even if the
 |      collection was added to the axes with *autolim* = True.
 |
 |      Note: there is no support for removing the artist's legend entry.
 |
 |  remove_callback(self, oid)
 |      Remove a callback based on its observer id.
 |
 |      See Also
 |      --------
 |      add_callback
 |
 |  set(self, **kwargs)
 |      A property batch setter.  Pass *kwargs* to set properties.
 |
 |  set_agg_filter(self, filter_func)
 |      Set the agg filter.
 |
 |      Parameters
 |      ----------
 |      filter_func : callable
 |          A filter function, which takes a (m, n, 3) float array and a dpi
 |          value, and returns a (m, n, 3) array.
 |
 |          .. ACCEPTS: a filter function, which takes a (m, n, 3) float array
 |              and a dpi value, and returns a (m, n, 3) array
 |
 |  set_animated(self, b)
 |      Set the artist's animation state.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_clip_box(self, clipbox)
 |      Set the artist's clip `.Bbox`.
 |
 |      Parameters
 |      ----------
 |      clipbox : `.Bbox`
 |
 |  set_clip_on(self, b)
 |      Set whether the artist uses clipping.
 |
 |      When False artists will be visible outside of the axes which
 |      can lead to unexpected results.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_clip_path(self, path, transform=None)
 |      Set the artist's clip path.
 |
 |      Parameters
 |      ----------
 |      path : `.Patch` or `.Path` or `.TransformedPath` or None
 |          The clip path. If given a `.Path`, *transform* must be provided as
 |          well. If *None*, a previously set clip path is removed.
 |      transform : `~matplotlib.transforms.Transform`, optional
 |          Only used if *path* is a `.Path`, in which case the given `.Path`
 |          is converted to a `.TransformedPath` using *transform*.
 |
 |      Notes
 |      -----
 |      For efficiency, if *path* is a `.Rectangle` this method will set the
 |      clipping box to the corresponding rectangle and set the clipping path
 |      to ``None``.
 |
 |      For technical reasons (support of `~.Artist.set`), a tuple
 |      (*path*, *transform*) is also accepted as a single positional
 |      parameter.
 |
 |      .. ACCEPTS: Patch or (Path, Transform) or None
 |
 |  set_contains(self, picker)
 |      [*Deprecated*] Define a custom contains syntax for the artist.
 |
 |      The provided callable replaces the default `.contains` method
 |      of the artist.
 |
 |      Parameters
 |      ----------
 |      picker : callable
 |          A custom picker function to evaluate if an event is within the
 |          artist. The function must have the signature::
 |
 |              def contains(artist: Artist, event: MouseEvent) -> bool, dict
 |
 |          that returns:
 |
 |          - a bool indicating if the event is within the artist
 |          - a dict of additional information. The dict should at least
 |            return the same information as the default ``contains()``
 |            implementation of the respective artist, but may provide
 |            additional information.
 |
 |      Notes
 |      -----
 |      .. deprecated:: 3.3
 |
 |  set_figure(self, fig)
 |      Set the `.Figure` instance the artist belongs to.
 |
 |      Parameters
 |      ----------
 |      fig : `.Figure`
 |
 |  set_gid(self, gid)
 |      Set the (group) id for the artist.
 |
 |      Parameters
 |      ----------
 |      gid : str
 |
 |  set_in_layout(self, in_layout)
 |      Set if artist is to be included in layout calculations,
 |      E.g. :doc:`/tutorials/intermediate/constrainedlayout_guide`,
 |      `.Figure.tight_layout()`, and
 |      ``fig.savefig(fname, bbox_inches='tight')``.
 |
 |      Parameters
 |      ----------
 |      in_layout : bool
 |
 |  set_label(self, s)
 |      Set a label that will be displayed in the legend.
 |
 |      Parameters
 |      ----------
 |      s : object
 |          *s* will be converted to a string by calling `str`.
 |
 |  set_path_effects(self, path_effects)
 |      Set the path effects.
 |
 |      Parameters
 |      ----------
 |      path_effects : `.AbstractPathEffect`
 |
 |  set_picker(self, picker)
 |      Define the picking behavior of the artist.
 |
 |      Parameters
 |      ----------
 |      picker : None or bool or callable
 |          This can be one of the following:
 |
 |          - *None*: Picking is disabled for this artist (default).
 |
 |          - A boolean: If *True* then picking will be enabled and the
 |            artist will fire a pick event if the mouse event is over
 |            the artist.
 |
 |          - A function: If picker is callable, it is a user supplied
 |            function which determines whether the artist is hit by the
 |            mouse event::
 |
 |              hit, props = picker(artist, mouseevent)
 |
 |            to determine the hit syntax.  if the mouse event is over the
 |            artist, return *hit=True* and props is a dictionary of
 |            properties you want added to the PickEvent attributes.
 |
 |          - *deprecated*: For `.Line2D` only, *picker* can also be a float
 |            that sets the tolerance for checking whether an event occurred
 |            "on" the line; this is deprecated.  Use `.Line2D.set_pickradius`
 |            instead.
 |
 |  set_rasterized(self, rasterized)
 |      Force rasterized (bitmap) drawing in vector backend output.
 |
 |      Defaults to None, which implies the backend's default behavior.
 |
 |      Parameters
 |      ----------
 |      rasterized : bool or None
 |
 |  set_sketch_params(self, scale=None, length=None, randomness=None)
 |      Sets the sketch parameters.
 |
 |      Parameters
 |      ----------
 |      scale : float, optional
 |          The amplitude of the wiggle perpendicular to the source
 |          line, in pixels.  If scale is `None`, or not provided, no
 |          sketch filter will be provided.
 |      length : float, optional
 |           The length of the wiggle along the line, in pixels
 |           (default 128.0)
 |      randomness : float, optional
 |          The scale factor by which the length is shrunken or
 |          expanded (default 16.0)
 |
 |          .. ACCEPTS: (scale: float, length: float, randomness: float)
 |
 |  set_snap(self, snap)
 |      Set the snapping behavior.
 |
 |      Snapping aligns positions with the pixel grid, which results in
 |      clearer images. For example, if a black line of 1px width was
 |      defined at a position in between two pixels, the resulting image
 |      would contain the interpolated value of that line in the pixel grid,
 |      which would be a grey value on both adjacent pixel positions. In
 |      contrast, snapping will move the line to the nearest integer pixel
 |      value, so that the resulting image will really contain a 1px wide
 |      black line.
 |
 |      Snapping is currently only supported by the Agg and MacOSX backends.
 |
 |      Parameters
 |      ----------
 |      snap : bool or None
 |          Possible values:
 |
 |          - *True*: Snap vertices to the nearest pixel center.
 |          - *False*: Do not modify vertex positions.
 |          - *None*: (auto) If the path contains only rectilinear line
 |            segments, round to the nearest pixel center.
 |
 |  set_transform(self, t)
 |      Set the artist transform.
 |
 |      Parameters
 |      ----------
 |      t : `.Transform`
 |
 |  set_url(self, url)
 |      Set the url for the artist.
 |
 |      Parameters
 |      ----------
 |      url : str
 |
 |  set_visible(self, b)
 |      Set the artist's visibility.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_zorder(self, level)
 |      Set the zorder for the artist.  Artists with lower zorder
 |      values are drawn first.
 |
 |      Parameters
 |      ----------
 |      level : float
 |
 |  update(self, props)
 |      Update this artist's properties from the dict *props*.
 |
 |      Parameters
 |      ----------
 |      props : dict
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from matplotlib.artist.Artist:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)
 |
 |  axes
 |      The `~.axes.Axes` instance the artist resides in, or *None*.
 |
 |  mouseover
 |      If this property is set to *True*, the artist will be queried for
 |      custom context information when the mouse cursor moves over it.
 |
 |      See also :meth:`get_cursor_data`, :class:`.ToolCursorPosition` and
 |      :class:`.NavigationToolbar2`.
 |
 |  stale
 |      Whether the artist is 'stale' and needs to be re-drawn for the output
 |      to match the internal state of the artist.
 |
 |  sticky_edges
 |      ``x`` and ``y`` sticky edge lists for autoscaling.
 |
 |      When performing autoscaling, if a data limit coincides with a value in
 |      the corresponding sticky_edges list, then no margin will be added--the
 |      view limit "sticks" to the edge. A typical use case is histograms,
 |      where one usually expects no margin on the bottom edge (0) of the
 |      histogram.
 |
 |      This attribute cannot be assigned to; however, the ``x`` and ``y``
 |      lists can be modified in place as needed.
 |
 |      Examples
 |      --------
 |      >>> artist.sticky_edges.x[:] = (xmin, xmax)
 |      >>> artist.sticky_edges.y[:] = (ymin, ymax)
        """
        # 导入patches模块，使用其包含的矩形Rectangle类型
        import matplotlib.patches as patches

        # 创建 3*3 坐标系画板
        fig, ax = plt.subplots(3, 3)

        # 设置每个坐标系的轴域
        [ax[i, j].set(xlim=(0, 5), ylim=(0,5)) for i in range(3) for j in range(3)]

        # 放置注释的坐标
        xytext = (0.1, 4.6)

        # 获取矩阵的顶边中点坐标, 作为标注点坐标
        rec_xywh = lambda rect: (rect.get_x(), rect.get_y(), rect.get_height(), rect.get_width())
        rec_top = lambda rect: (rect.get_x()+rect.get_width()/2,
                                rect.get_y()+rect.get_height()*(1 if rect.get_height() > 0 else 0))

        # 绘制第1个矩阵
        rect1 = patches.Rectangle(xy=(0, 0), width=3, height=2.5, color='b')
        ax[0, 0].add_patch(rect1)
        ax[0, 0].annotate(xytext=xytext,
                          xy=rec_top(rect1),
                          text="xy=(0, 0), width=3, height=2.5\ncolor='b'",
                          va='top',
                          arrowprops=dict(width=1),
                          bbox=dict(pad=5, alpha=0.2)
                          )

        # 绘制第2个矩阵
        rect2 = patches.Rectangle(xy=(1, 0.2), width=3, height=2.5, facecolor='grey', edgecolor='r', linewidth=3)
        ax[0, 1].add_patch(rect2)
        ax[0, 1].annotate(xytext=xytext,
                          xy=rec_top(rect2),
                          text="xy=(1, 0.2), width=3, height=2.5\nfacecolor='grey'"
                               ", edgecolor='r'\nlinewidth=3",
                          va='top',
                          arrowprops=dict(width=1),
                          bbox=dict(pad=5, alpha=0.2)
                          )

        rect3 = patches.Rectangle(xy=(2, 1), width=2, height=2, color='purple', angle=15)
        ax[0, 2].add_patch(rect3)
        ax[0, 2].annotate(xytext=xytext,
                          xy=rec_top(rect3),
                          text="xy=(2, 1), width=2, height=2\ncolor='purple, angle=15",
                          va='top',
                          arrowprops=dict(width=1),
                          bbox=dict(pad=5, alpha=0.2)
                          )

        rect4 = patches.Rectangle(xy=(2, 0), width=2, height=2, color='lightgreen', fill=False)
        ax[1, 0].add_patch(rect4)
        ax[1, 0].annotate(xytext=xytext,
                          xy=rec_top(rect4),
                          text="xy=(2, 0), width=2, height=2\ncolor='lightgreen', fill=False",
                          va='top',
                          arrowprops=dict(width=1),
                          bbox=dict(pad=5, alpha=0.2)
                          )

        rect5 = patches.Rectangle(xy=(5, 0), width=-2, height=2, hatch='x')
        ax[1, 1].add_patch(rect5)
        ax[1, 1].annotate(xytext=xytext,
                          xy=rec_top(rect5),
                          text="xy=(5, 0), width=-2, height=2\nhatch='x'",
                          va='top',
                          arrowprops=dict(width=1),
                          bbox=dict(pad=5, alpha=0.2)
                          )

        rect6 = patches.Rectangle(xy=(5, 2), width=-3, height=-1.5, hatch='*')
        ax[1, 2].add_patch(rect6)
        ax[1, 2].annotate(xytext=xytext,
                          xy=rec_top(rect6),
                          text="xy=(5, 2), width=-3, height=-1.5\nhatch='*'",
                          va='top',
                          bbox=dict(pad=5, alpha=0.2),
                          arrowprops=dict(arrowstyle="-|>", relpos=(0.5, 0.5))
                          )

        rect7 = patches.Rectangle(xy=(1, 1), width=3, height=-1.5, linewidth=3, edgecolor='y')
        ax[2, 0].add_patch(rect7)
        ax[2, 0].annotate(xytext=xytext,
                          xy=rec_top(rect7),
                          text="xy=(1, 1), width=3, height=-1.5\nlinewidth=3, edgecolor='y'",
                          va='top',
                          bbox=dict(pad=5, alpha=0.2),
                          arrowprops=dict(arrowstyle="-|>", relpos=(0, 0))
                          )

        rect8 = patches.Rectangle(xy=(4.5, 2), width=-3, height=-1.5,edgecolor='pink', linewidth=6, joinstyle='bevel')
        # no effect: joinstyle='round'
        ax[2, 1].add_patch(rect8)
        ax[2, 1].annotate(xytext=xytext,
                          xy=rec_top(rect8),
                          text="xy=(5, 2), width=-3, height=-1.5\nedgecolor='r', linewidth=6\njoinstyle='round'",
                          va='top',
                          arrowprops=dict(width=1),
                          bbox=dict(pad=5, alpha=0.2),
                          )

        rect9 = patches.Rectangle(xy=(5, 3), width=-3, height=-1.5, facecolor='#808069', angle=-15)
        ax[2, 2].add_patch(rect9)
        ann = ax[2, 2].annotate(
            xytext=xytext,
            xy=rec_top(rect9),
            text="xy=(5, 3), width=-3, height=-1.5\nfacecolor='#808069', angle=0.35",
            va='top',
            arrowprops=dict(arrowstyle="-|>", relpos=(0.5, 0.5),
                            mutation_scale=20),
            bbox=dict(pad=5, alpha=0.2),
            )
        plt.gcf().set_size_inches(18, 10)

    @staticmethod
    def polygon():
        """
class Polygon(Patch)
 |  Polygon(xy, closed=True, **kwargs)
 |
 |  A general polygon patch.
 |
 |  Method resolution order:
 |      Polygon
 |      Patch
 |      matplotlib.artist.Artist
 |      builtins.object
 |
 |  Methods defined here:
 |
 |  __init__(self, xy, closed=True, **kwargs)
 |      *xy* is a numpy array with shape Nx2.
 |
 |      If *closed* is *True*, the polygon will be closed so the
 |      starting and ending points are the same.
 |
 |      Valid keyword arguments are:
 |
 |      Properties:
 |          agg_filter: a filter function, which takes a (m, n, 3) float array and a dpi value, and returns a (m, n, 3) array
 |          alpha: float or None
 |          animated: bool
 |          antialiased or aa: unknown
 |          capstyle: {'butt', 'round', 'projecting'}
 |          clip_box: `.Bbox`
 |          clip_on: bool
 |          clip_path: Patch or (Path, Transform) or None
 |          color: color
 |          contains: unknown
 |          edgecolor or ec: color or None or 'auto'
 |          facecolor or fc: color or None
 |          figure: `.Figure`
 |          fill: bool
 |          gid: str
 |          hatch: {'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
 |          in_layout: bool
 |          joinstyle: {'miter', 'round', 'bevel'}
 |          label: object
 |          linestyle or ls: {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
 |          linewidth or lw: float or None
 |          path_effects: `.AbstractPathEffect`
 |          picker: None or bool or callable
 |          rasterized: bool or None
 |          sketch_params: (scale: float, length: float, randomness: float)
 |          snap: bool or None
 |          transform: `.Transform`
 |          url: str
 |          visible: bool
 |          zorder: float
 |
 |  __str__(self)
 |      Return str(self).
 |
 |  get_closed(self)
 |      Return whether the polygon is closed.
 |
 |  get_path(self)
 |      Get the `.Path` of the polygon.
 |
 |  get_xy(self)
 |      Get the vertices of the path.
 |
 |      Returns
 |      -------
 |      (N, 2) numpy array
 |          The coordinates of the vertices.
 |
 |  set_closed(self, closed)
 |      Set whether the polygon is closed.
 |
 |      Parameters
 |      ----------
 |      closed : bool
 |         True if the polygon is closed
 |
 |  set_xy(self, xy)
 |      Set the vertices of the polygon.
 |
 |      Parameters
 |      ----------
 |      xy : (N, 2) array-like
 |          The coordinates of the vertices.
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |
 |  xy
 |      The vertices of the path as (N, 2) numpy array.
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from Patch:
 |
 |  contains(self, mouseevent, radius=None)
 |      Test whether the mouse event occurred in the patch.
 |
 |      Returns
 |      -------
 |      (bool, empty dict)
 |
 |  contains_point(self, point, radius=None)
 |      Return whether the given point is inside the patch.
 |
 |      Parameters
 |      ----------
 |      point : (float, float)
 |          The point (x, y) to check, in target coordinates of
 |          ``self.get_transform()``. These are display coordinates for patches
 |          that are added to a figure or axes.
 |      radius : float, optional
 |          Add an additional margin on the patch in target coordinates of
 |          ``self.get_transform()``. See `.Path.contains_point` for further
 |          details.
 |
 |      Returns
 |      -------
 |      bool
 |
 |      Notes
 |      -----
 |      The proper use of this method depends on the transform of the patch.
 |      Isolated patches do not have a transform. In this case, the patch
 |      creation coordinates and the point coordinates match. The following
 |      example checks that the center of a circle is within the circle
 |
 |      >>> center = 0, 0
 |      >>> c = Circle(center, radius=1)
 |      >>> c.contains_point(center)
 |      True
 |
 |      The convention of checking against the transformed patch stems from
 |      the fact that this method is predominantly used to check if display
 |      coordinates (e.g. from mouse events) are within the patch. If you want
 |      to do the above check with data coordinates, you have to properly
 |      transform them first:
 |
 |      >>> center = 0, 0
 |      >>> c = Circle(center, radius=1)
 |      >>> plt.gca().add_patch(c)
 |      >>> transformed_center = c.get_transform().transform(center)
 |      >>> c.contains_point(transformed_center)
 |      True
 |
 |  contains_points(self, points, radius=None)
 |      Return whether the given points are inside the patch.
 |
 |      Parameters
 |      ----------
 |      points : (N, 2) array
 |          The points to check, in target coordinates of
 |          ``self.get_transform()``. These are display coordinates for patches
 |          that are added to a figure or axes. Columns contain x and y values.
 |      radius : float, optional
 |          Add an additional margin on the patch in target coordinates of
 |          ``self.get_transform()``. See `.Path.contains_point` for further
 |          details.
 |
 |      Returns
 |      -------
 |      length-N bool array
 |
 |      Notes
 |      -----
 |      The proper use of this method depends on the transform of the patch.
 |      See the notes on `.Patch.contains_point`.
 |
 |  draw(self, renderer)
 |      Draw the Artist (and its children) using the given renderer.
 |
 |      This has no effect if the artist is not visible (`.Artist.get_visible`
 |      returns False).
 |
 |      Parameters
 |      ----------
 |      renderer : `.RendererBase` subclass.
 |
 |      Notes
 |      -----
 |      This method is overridden in the Artist subclasses.
 |
 |  get_aa(self)
 |      Alias for `get_antialiased`.
 |
 |  get_antialiased(self)
 |      Return whether antialiasing is used for drawing.
 |
 |  get_capstyle(self)
 |      Return the capstyle.
 |
 |  get_data_transform(self)
 |      Return the `~.transforms.Transform` mapping data coordinates to
 |      physical coordinates.
 |
 |  get_ec(self)
 |      Alias for `get_edgecolor`.
 |
 |  get_edgecolor(self)
 |      Return the edge color.
 |
 |  get_extents(self)
 |      Return the `Patch`'s axis-aligned extents as a `~.transforms.Bbox`.
 |
 |  get_facecolor(self)
 |      Return the face color.
 |
 |  get_fc(self)
 |      Alias for `get_facecolor`.
 |
 |  get_fill(self)
 |      Return whether the patch is filled.
 |
 |  get_hatch(self)
 |      Return the hatching pattern.
 |
 |  get_joinstyle(self)
 |      Return the joinstyle.
 |
 |  get_linestyle(self)
 |      Return the linestyle.
 |
 |  get_linewidth(self)
 |      Return the line width in points.
 |
 |  get_ls(self)
 |      Alias for `get_linestyle`.
 |
 |  get_lw(self)
 |      Alias for `get_linewidth`.
 |
 |  get_patch_transform(self)
 |      Return the `~.transforms.Transform` instance mapping patch coordinates
 |      to data coordinates.
 |
 |      For example, one may define a patch of a circle which represents a
 |      radius of 5 by providing coordinates for a unit circle, and a
 |      transform which scales the coordinates (the patch coordinate) by 5.
 |
 |  get_transform(self)
 |      Return the `~.transforms.Transform` applied to the `Patch`.
 |
 |  get_verts(self)
 |      Return a copy of the vertices used in this patch.
 |
 |      If the patch contains Bezier curves, the curves will be interpolated by
 |      line segments.  To access the curves as curves, use `get_path`.
 |
 |  get_window_extent(self, renderer=None)
 |      Get the axes bounding box in display space.
 |
 |      The bounding box' width and height are nonnegative.
 |
 |      Subclasses should override for inclusion in the bounding box
 |      "tight" calculation. Default is to return an empty bounding
 |      box at 0, 0.
 |
 |      Be careful when using this function, the results will not update
 |      if the artist window extent of the artist changes.  The extent
 |      can change due to any changes in the transform stack, such as
 |      changing the axes limits, the figure size, or the canvas used
 |      (as is done when saving a figure).  This can lead to unexpected
 |      behavior where interactive figures will look fine on the screen,
 |      but will save incorrectly.
 |
 |  set_aa(self, aa)
 |      Alias for `set_antialiased`.
 |
 |  set_alpha(self, alpha)
 |      Set the alpha value used for blending - not supported on all backends.
 |
 |      Parameters
 |      ----------
 |      alpha : float or None
 |
 |  set_antialiased(self, aa)
 |      Set whether to use antialiased rendering.
 |
 |      Parameters
 |      ----------
 |      b : bool or None
 |
 |  set_capstyle(self, s)
 |      Set the capstyle.
 |
 |      Parameters
 |      ----------
 |      s : {'butt', 'round', 'projecting'}
 |
 |  set_color(self, c)
 |      Set both the edgecolor and the facecolor.
 |
 |      Parameters
 |      ----------
 |      c : color
 |
 |      See Also
 |      --------
 |      Patch.set_facecolor, Patch.set_edgecolor
 |          For setting the edge or face color individually.
 |
 |  set_ec(self, color)
 |      Alias for `set_edgecolor`.
 |
 |  set_edgecolor(self, color)
 |      Set the patch edge color.
 |
 |      Parameters
 |      ----------
 |      color : color or None or 'auto'
 |
 |  set_facecolor(self, color)
 |      Set the patch face color.
 |
 |      Parameters
 |      ----------
 |      color : color or None
 |
 |  set_fc(self, color)
 |      Alias for `set_facecolor`.
 |
 |  set_fill(self, b)
 |      Set whether to fill the patch.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_hatch(self, hatch)
 |      Set the hatching pattern.
 |
 |      *hatch* can be one of::
 |
 |        /   - diagonal hatching
 |        \   - back diagonal
 |        |   - vertical
 |        -   - horizontal
 |        +   - crossed
 |        x   - crossed diagonal
 |        o   - small circle
 |        O   - large circle
 |        .   - dots
 |        *   - stars
 |
 |      Letters can be combined, in which case all the specified
 |      hatchings are done.  If same letter repeats, it increases the
 |      density of hatching of that pattern.
 |
 |      Hatching is supported in the PostScript, PDF, SVG and Agg
 |      backends only.
 |
 |      Parameters
 |      ----------
 |      hatch : {'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
 |
 |  set_joinstyle(self, s)
 |      Set the joinstyle.
 |
 |      Parameters
 |      ----------
 |      s : {'miter', 'round', 'bevel'}
 |
 |  set_linestyle(self, ls)
 |      Set the patch linestyle.
 |
 |      ===========================   =================
 |      linestyle                     description
 |      ===========================   =================
 |      ``'-'`` or ``'solid'``        solid line
 |      ``'--'`` or  ``'dashed'``     dashed line
 |      ``'-.'`` or  ``'dashdot'``    dash-dotted line
 |      ``':'`` or ``'dotted'``       dotted line
 |      ===========================   =================
 |
 |      Alternatively a dash tuple of the following form can be provided::
 |
 |          (offset, onoffseq)
 |
 |      where ``onoffseq`` is an even length tuple of on and off ink in points.
 |
 |      Parameters
 |      ----------
 |      ls : {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
 |          The line style.
 |
 |  set_linewidth(self, w)
 |      Set the patch linewidth in points.
 |
 |      Parameters
 |      ----------
 |      w : float or None
 |
 |  set_ls(self, ls)
 |      Alias for `set_linestyle`.
 |
 |  set_lw(self, w)
 |      Alias for `set_linewidth`.
 |
 |  update_from(self, other)
 |      Copy properties from *other* to *self*.
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from Patch:
 |
 |  fill
 |      Return whether the patch is filled.
 |
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from Patch:
 |
 |  validCap = ('butt', 'round', 'projecting')
 |
 |  validJoin = ('miter', 'round', 'bevel')
 |
 |  zorder = 1
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from matplotlib.artist.Artist:
 |
 |  __getstate__(self)
 |
 |  add_callback(self, func)
 |      Add a callback function that will be called whenever one of the
 |      `.Artist`'s properties changes.
 |
 |      Parameters
 |      ----------
 |      func : callable
 |          The callback function. It must have the signature::
 |
 |              def func(artist: Artist) -> Any
 |
 |          where *artist* is the calling `.Artist`. Return values may exist
 |          but are ignored.
 |
 |      Returns
 |      -------
 |      int
 |          The observer id associated with the callback. This id can be
 |          used for removing the callback with `.remove_callback` later.
 |
 |      See Also
 |      --------
 |      remove_callback
 |
 |  convert_xunits(self, x)
 |      Convert *x* using the unit type of the xaxis.
 |
 |      If the artist is not in contained in an Axes or if the xaxis does not
 |      have units, *x* itself is returned.
 |
 |  convert_yunits(self, y)
 |      Convert *y* using the unit type of the yaxis.
 |
 |      If the artist is not in contained in an Axes or if the yaxis does not
 |      have units, *y* itself is returned.
 |
 |  findobj(self, match=None, include_self=True)
 |      Find artist objects.
 |
 |      Recursively find all `.Artist` instances contained in the artist.
 |
 |      Parameters
 |      ----------
 |      match
 |          A filter criterion for the matches. This can be
 |
 |          - *None*: Return all objects contained in artist.
 |          - A function with signature ``def match(artist: Artist) -> bool``.
 |            The result will only contain artists for which the function
 |            returns *True*.
 |          - A class instance: e.g., `.Line2D`. The result will only contain
 |            artists of this class or its subclasses (``isinstance`` check).
 |
 |      include_self : bool
 |          Include *self* in the list to be checked for a match.
 |
 |      Returns
 |      -------
 |      list of `.Artist`
 |
 |  format_cursor_data(self, data)
 |      Return a string representation of *data*.
 |
 |      .. note::
 |          This method is intended to be overridden by artist subclasses.
 |          As an end-user of Matplotlib you will most likely not call this
 |          method yourself.
 |
 |      The default implementation converts ints and floats and arrays of ints
 |      and floats into a comma-separated string enclosed in square brackets.
 |
 |      See Also
 |      --------
 |      get_cursor_data
 |
 |  get_agg_filter(self)
 |      Return filter function to be used for agg filter.
 |
 |  get_alpha(self)
 |      Return the alpha value used for blending - not supported on all
 |      backends.
 |
 |  get_animated(self)
 |      Return whether the artist is animated.
 |
 |  get_children(self)
 |      Return a list of the child `.Artist`\s of this `.Artist`.
 |
 |  get_clip_box(self)
 |      Return the clipbox.
 |
 |  get_clip_on(self)
 |      Return whether the artist uses clipping.
 |
 |  get_clip_path(self)
 |      Return the clip path.
 |
 |  get_contains(self)
 |      [*Deprecated*] Return the custom contains function of the artist if set, or *None*.
 |
 |      See Also
 |      --------
 |      set_contains
 |
 |      Notes
 |      -----
 |      .. deprecated:: 3.3
 |
 |  get_cursor_data(self, event)
 |      Return the cursor data for a given event.
 |
 |      .. note::
 |          This method is intended to be overridden by artist subclasses.
 |          As an end-user of Matplotlib you will most likely not call this
 |          method yourself.
 |
 |      Cursor data can be used by Artists to provide additional context
 |      information for a given event. The default implementation just returns
 |      *None*.
 |
 |      Subclasses can override the method and return arbitrary data. However,
 |      when doing so, they must ensure that `.format_cursor_data` can convert
 |      the data to a string representation.
 |
 |      The only current use case is displaying the z-value of an `.AxesImage`
 |      in the status bar of a plot window, while moving the mouse.
 |
 |      Parameters
 |      ----------
 |      event : `matplotlib.backend_bases.MouseEvent`
 |
 |      See Also
 |      --------
 |      format_cursor_data
 |
 |  get_figure(self)
 |      Return the `.Figure` instance the artist belongs to.
 |
 |  get_gid(self)
 |      Return the group id.
 |
 |  get_in_layout(self)
 |      Return boolean flag, ``True`` if artist is included in layout
 |      calculations.
 |
 |      E.g. :doc:`/tutorials/intermediate/constrainedlayout_guide`,
 |      `.Figure.tight_layout()`, and
 |      ``fig.savefig(fname, bbox_inches='tight')``.
 |
 |  get_label(self)
 |      Return the label used for this artist in the legend.
 |
 |  get_path_effects(self)
 |
 |  get_picker(self)
 |      Return the picking behavior of the artist.
 |
 |      The possible values are described in `.set_picker`.
 |
 |      See Also
 |      --------
 |      set_picker, pickable, pick
 |
 |  get_rasterized(self)
 |      Return whether the artist is to be rasterized.
 |
 |  get_sketch_params(self)
 |      Return the sketch parameters for the artist.
 |
 |      Returns
 |      -------
 |      tuple or None
 |
 |          A 3-tuple with the following elements:
 |
 |          - *scale*: The amplitude of the wiggle perpendicular to the
 |            source line.
 |          - *length*: The length of the wiggle along the line.
 |          - *randomness*: The scale factor by which the length is
 |            shrunken or expanded.
 |
 |          Returns *None* if no sketch parameters were set.
 |
 |  get_snap(self)
 |      Return the snap setting.
 |
 |      See `.set_snap` for details.
 |
 |  get_tightbbox(self, renderer)
 |      Like `.Artist.get_window_extent`, but includes any clipping.
 |
 |      Parameters
 |      ----------
 |      renderer : `.RendererBase` subclass
 |          renderer that will be used to draw the figures (i.e.
 |          ``fig.canvas.get_renderer()``)
 |
 |      Returns
 |      -------
 |      `.Bbox`
 |          The enclosing bounding box (in figure pixel coordinates).
 |
 |  get_transformed_clip_path_and_affine(self)
 |      Return the clip path with the non-affine part of its
 |      transformation applied, and the remaining affine part of its
 |      transformation.
 |
 |  get_url(self)
 |      Return the url.
 |
 |  get_visible(self)
 |      Return the visibility.
 |
 |  get_zorder(self)
 |      Return the artist's zorder.
 |
 |  have_units(self)
 |      Return *True* if units are set on any axis.
 |
 |  is_transform_set(self)
 |      Return whether the Artist has an explicitly set transform.
 |
 |      This is *True* after `.set_transform` has been called.
 |
 |  pchanged(self)
 |      Call all of the registered callbacks.
 |
 |      This function is triggered internally when a property is changed.
 |
 |      See Also
 |      --------
 |      add_callback
 |      remove_callback
 |
 |  pick(self, mouseevent)
 |      Process a pick event.
 |
 |      Each child artist will fire a pick event if *mouseevent* is over
 |      the artist and the artist has picker set.
 |
 |      See Also
 |      --------
 |      set_picker, get_picker, pickable
 |
 |  pickable(self)
 |      Return whether the artist is pickable.
 |
 |      See Also
 |      --------
 |      set_picker, get_picker, pick
 |
 |  properties(self)
 |      Return a dictionary of all the properties of the artist.
 |
 |  remove(self)
 |      Remove the artist from the figure if possible.
 |
 |      The effect will not be visible until the figure is redrawn, e.g.,
 |      with `.FigureCanvasBase.draw_idle`.  Call `~.axes.Axes.relim` to
 |      update the axes limits if desired.
 |
 |      Note: `~.axes.Axes.relim` will not see collections even if the
 |      collection was added to the axes with *autolim* = True.
 |
 |      Note: there is no support for removing the artist's legend entry.
 |
 |  remove_callback(self, oid)
 |      Remove a callback based on its observer id.
 |
 |      See Also
 |      --------
 |      add_callback
 |
 |  set(self, **kwargs)
 |      A property batch setter.  Pass *kwargs* to set properties.
 |
 |  set_agg_filter(self, filter_func)
 |      Set the agg filter.
 |
 |      Parameters
 |      ----------
 |      filter_func : callable
 |          A filter function, which takes a (m, n, 3) float array and a dpi
 |          value, and returns a (m, n, 3) array.
 |
 |          .. ACCEPTS: a filter function, which takes a (m, n, 3) float array
 |              and a dpi value, and returns a (m, n, 3) array
 |
 |  set_animated(self, b)
 |      Set the artist's animation state.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_clip_box(self, clipbox)
 |      Set the artist's clip `.Bbox`.
 |
 |      Parameters
 |      ----------
 |      clipbox : `.Bbox`
 |
 |  set_clip_on(self, b)
 |      Set whether the artist uses clipping.
 |
 |      When False artists will be visible outside of the axes which
 |      can lead to unexpected results.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_clip_path(self, path, transform=None)
 |      Set the artist's clip path.
 |
 |      Parameters
 |      ----------
 |      path : `.Patch` or `.Path` or `.TransformedPath` or None
 |          The clip path. If given a `.Path`, *transform* must be provided as
 |          well. If *None*, a previously set clip path is removed.
 |      transform : `~matplotlib.transforms.Transform`, optional
 |          Only used if *path* is a `.Path`, in which case the given `.Path`
 |          is converted to a `.TransformedPath` using *transform*.
 |
 |      Notes
 |      -----
 |      For efficiency, if *path* is a `.Rectangle` this method will set the
 |      clipping box to the corresponding rectangle and set the clipping path
 |      to ``None``.
 |
 |      For technical reasons (support of `~.Artist.set`), a tuple
 |      (*path*, *transform*) is also accepted as a single positional
 |      parameter.
 |
 |      .. ACCEPTS: Patch or (Path, Transform) or None
 |
 |  set_contains(self, picker)
 |      [*Deprecated*] Define a custom contains syntax for the artist.
 |
 |      The provided callable replaces the default `.contains` method
 |      of the artist.
 |
 |      Parameters
 |      ----------
 |      picker : callable
 |          A custom picker function to evaluate if an event is within the
 |          artist. The function must have the signature::
 |
 |              def contains(artist: Artist, event: MouseEvent) -> bool, dict
 |
 |          that returns:
 |
 |          - a bool indicating if the event is within the artist
 |          - a dict of additional information. The dict should at least
 |            return the same information as the default ``contains()``
 |            implementation of the respective artist, but may provide
 |            additional information.
 |
 |      Notes
 |      -----
 |      .. deprecated:: 3.3
 |
 |  set_figure(self, fig)
 |      Set the `.Figure` instance the artist belongs to.
 |
 |      Parameters
 |      ----------
 |      fig : `.Figure`
 |
 |  set_gid(self, gid)
 |      Set the (group) id for the artist.
 |
 |      Parameters
 |      ----------
 |      gid : str
 |
 |  set_in_layout(self, in_layout)
 |      Set if artist is to be included in layout calculations,
 |      E.g. :doc:`/tutorials/intermediate/constrainedlayout_guide`,
 |      `.Figure.tight_layout()`, and
 |      ``fig.savefig(fname, bbox_inches='tight')``.
 |
 |      Parameters
 |      ----------
 |      in_layout : bool
 |
 |  set_label(self, s)
 |      Set a label that will be displayed in the legend.
 |
 |      Parameters
 |      ----------
 |      s : object
 |          *s* will be converted to a string by calling `str`.
 |
 |  set_path_effects(self, path_effects)
 |      Set the path effects.
 |
 |      Parameters
 |      ----------
 |      path_effects : `.AbstractPathEffect`
 |
 |  set_picker(self, picker)
 |      Define the picking behavior of the artist.
 |
 |      Parameters
 |      ----------
 |      picker : None or bool or callable
 |          This can be one of the following:
 |
 |          - *None*: Picking is disabled for this artist (default).
 |
 |          - A boolean: If *True* then picking will be enabled and the
 |            artist will fire a pick event if the mouse event is over
 |            the artist.
 |
 |          - A function: If picker is callable, it is a user supplied
 |            function which determines whether the artist is hit by the
 |            mouse event::
 |
 |              hit, props = picker(artist, mouseevent)
 |
 |            to determine the hit syntax.  if the mouse event is over the
 |            artist, return *hit=True* and props is a dictionary of
 |            properties you want added to the PickEvent attributes.
 |
 |          - *deprecated*: For `.Line2D` only, *picker* can also be a float
 |            that sets the tolerance for checking whether an event occurred
 |            "on" the line; this is deprecated.  Use `.Line2D.set_pickradius`
 |            instead.
 |
 |  set_rasterized(self, rasterized)
 |      Force rasterized (bitmap) drawing in vector backend output.
 |
 |      Defaults to None, which implies the backend's default behavior.
 |
 |      Parameters
 |      ----------
 |      rasterized : bool or None
 |
 |  set_sketch_params(self, scale=None, length=None, randomness=None)
 |      Sets the sketch parameters.
 |
 |      Parameters
 |      ----------
 |      scale : float, optional
 |          The amplitude of the wiggle perpendicular to the source
 |          line, in pixels.  If scale is `None`, or not provided, no
 |          sketch filter will be provided.
 |      length : float, optional
 |           The length of the wiggle along the line, in pixels
 |           (default 128.0)
 |      randomness : float, optional
 |          The scale factor by which the length is shrunken or
 |          expanded (default 16.0)
 |
 |          .. ACCEPTS: (scale: float, length: float, randomness: float)
 |
 |  set_snap(self, snap)
 |      Set the snapping behavior.
 |
 |      Snapping aligns positions with the pixel grid, which results in
 |      clearer images. For example, if a black line of 1px width was
 |      defined at a position in between two pixels, the resulting image
 |      would contain the interpolated value of that line in the pixel grid,
 |      which would be a grey value on both adjacent pixel positions. In
 |      contrast, snapping will move the line to the nearest integer pixel
 |      value, so that the resulting image will really contain a 1px wide
 |      black line.
 |
 |      Snapping is currently only supported by the Agg and MacOSX backends.
 |
 |      Parameters
 |      ----------
 |      snap : bool or None
 |          Possible values:
 |
 |          - *True*: Snap vertices to the nearest pixel center.
 |          - *False*: Do not modify vertex positions.
 |          - *None*: (auto) If the path contains only rectilinear line
 |            segments, round to the nearest pixel center.
 |
 |  set_transform(self, t)
 |      Set the artist transform.
 |
 |      Parameters
 |      ----------
 |      t : `.Transform`
 |
 |  set_url(self, url)
 |      Set the url for the artist.
 |
 |      Parameters
 |      ----------
 |      url : str
 |
 |  set_visible(self, b)
 |      Set the artist's visibility.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_zorder(self, level)
 |      Set the zorder for the artist.  Artists with lower zorder
 |      values are drawn first.
 |
 |      Parameters
 |      ----------
 |      level : float
 |
 |  update(self, props)
 |      Update this artist's properties from the dict *props*.
 |
 |      Parameters
 |      ----------
 |      props : dict
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from matplotlib.artist.Artist:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)
 |
 |  axes
 |      The `~.axes.Axes` instance the artist resides in, or *None*.
 |
 |  mouseover
 |      If this property is set to *True*, the artist will be queried for
 |      custom context information when the mouse cursor moves over it.
 |
 |      See also :meth:`get_cursor_data`, :class:`.ToolCursorPosition` and
 |      :class:`.NavigationToolbar2`.
 |
 |  stale
 |      Whether the artist is 'stale' and needs to be re-drawn for the output
 |      to match the internal state of the artist.
 |
 |  sticky_edges
 |      ``x`` and ``y`` sticky edge lists for autoscaling.
 |
 |      When performing autoscaling, if a data limit coincides with a value in
 |      the corresponding sticky_edges list, then no margin will be added--the
 |      view limit "sticks" to the edge. A typical use case is histograms,
 |      where one usually expects no margin on the bottom edge (0) of the
 |      histogram.
 |
 |      This attribute cannot be assigned to; however, the ``x`` and ``y``
 |      lists can be modified in place as needed.
 |
 |      Examples
 |      --------
 |      >>> artist.sticky_edges.x[:] = (xmin, xmax)
 |      >>> artist.sticky_edges.y[:] = (ymin, ymax)
        """
        fig, ax = plt.subplots()
        triagle = [[0.1, 0.5], [1.1, 0.5], [0.6, np.sqrt(3)/2+0.5]]
        rectangle = [(1.5, 0.5), (2.5, 0.5), (2.5, 1.5), (1.5, 1.5)]
        # pengaton = [(4.5, 0.5),
        #             (5.5, 0.5),
        #             ((5.5-4.5)*np.cos(65/360*2*np.pi) + 5.5, (5.5-4.5)*np.sin(65/360*2*np.pi) + 0.5),
        #             ((5.5-4.5)/2, (5.5-4.5)*np.tan(57.5/360*2*np.pi)**-1),
        #             (4.5-(5.5-4.5)*np.cos(65/360*2*np.pi), (5.5-4.5)*np.sin(65/360*2*np.pi) + 0.5)
        #             ]
        hexagon = [(3.5, 0.5),
                   (4.5, 0.5),
                   (5, 0.5+np.sqrt(3)/2),
                   (4.5, 0.5+np.sqrt(3)),
                   (3.5, 0.5+np.sqrt(3)),
                   (3, 0.5+np.sqrt(3)/2)]
        polygons = [triagle, rectangle, hexagon]
        colors = ['y', 'g', 'b']
        hatchs = ['*', 'x', 'O']
        alphas = [0.2, 0.3, 0.6]
        for j, vertex in enumerate(polygons):
            polygon = DemoPatch.patches.Polygon(
                xy=vertex, closed=True, facecolor=colors[j], hatch=hatchs[j], alpha=alphas[j],
                edgecolor='r', linewidth=3)
            ax.add_patch(polygon)
        ax.set(xlim=(0, 5.5), ylim=(0, 3))

    @staticmethod
    def ellipse():
        """
class Ellipse(Patch)
 |  Ellipse(xy, width, height, angle=0, **kwargs)
 |
 |  A scale-free ellipse.
 |
 |  Method resolution order:
 |      Ellipse
 |      Patch
 |      matplotlib.artist.Artist
 |      builtins.object
 |
 |  Methods defined here:
 |
 |  __init__(self, xy, width, height, angle=0, **kwargs)
 |      Parameters
 |      ----------
 |      xy : (float, float)
 |          xy coordinates of ellipse centre.
 |      width : float
 |          Total length (diameter) of horizontal axis.
 |      height : float
 |          Total length (diameter) of vertical axis.
 |      angle : float, default: 0
 |          Rotation in degrees anti-clockwise.
 |
 |      Notes
 |      -----
 |      Valid keyword arguments are:
 |
 |      Properties:
 |          agg_filter: a filter function, which takes a (m, n, 3) float array and a dpi value, and returns a (m, n, 3) array
 |          alpha: float or None
 |          animated: bool
 |          antialiased or aa: unknown
 |          capstyle: {'butt', 'round', 'projecting'}
 |          clip_box: `.Bbox`
 |          clip_on: bool
 |          clip_path: Patch or (Path, Transform) or None
 |          color: color
 |          contains: unknown
 |          edgecolor or ec: color or None or 'auto'
 |          facecolor or fc: color or None
 |          figure: `.Figure`
 |          fill: bool
 |          gid: str
 |          hatch: {'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
 |          in_layout: bool
 |          joinstyle: {'miter', 'round', 'bevel'}
 |          label: object
 |          linestyle or ls: {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
 |          linewidth or lw: float or None
 |          path_effects: `.AbstractPathEffect`
 |          picker: None or bool or callable
 |          rasterized: bool or None
 |          sketch_params: (scale: float, length: float, randomness: float)
 |          snap: bool or None
 |          transform: `.Transform`
 |          url: str
 |          visible: bool
 |          zorder: float
 |
 |  __str__(self)
 |      Return str(self).
 |
 |  get_angle(self)
 |      Return the angle of the ellipse.
 |
 |  get_center(self)
 |      Return the center of the ellipse.
 |
 |  get_height(self)
 |      Return the height of the ellipse.
 |
 |  get_patch_transform(self)
 |      Return the `~.transforms.Transform` instance mapping patch coordinates
 |      to data coordinates.
 |
 |      For example, one may define a patch of a circle which represents a
 |      radius of 5 by providing coordinates for a unit circle, and a
 |      transform which scales the coordinates (the patch coordinate) by 5.
 |
 |  get_path(self)
 |      Return the path of the ellipse.
 |
 |  get_width(self)
 |      Return the width of the ellipse.
 |
 |  set_angle(self, angle)
 |      Set the angle of the ellipse.
 |
 |      Parameters
 |      ----------
 |      angle : float
 |
 |  set_center(self, xy)
 |      Set the center of the ellipse.
 |
 |      Parameters
 |      ----------
 |      xy : (float, float)
 |
 |  set_height(self, height)
 |      Set the height of the ellipse.
 |
 |      Parameters
 |      ----------
 |      height : float
 |
 |  set_width(self, width)
 |      Set the width of the ellipse.
 |
 |      Parameters
 |      ----------
 |      width : float
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |
 |  angle
 |      Return the angle of the ellipse.
 |
 |  center
 |      Return the center of the ellipse.
 |
 |  height
 |      Return the height of the ellipse.
 |
 |  width
 |      Return the width of the ellipse.
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from Patch:
 |
 |  contains(self, mouseevent, radius=None)
 |      Test whether the mouse event occurred in the patch.
 |
 |      Returns
 |      -------
 |      (bool, empty dict)
 |
 |  contains_point(self, point, radius=None)
 |      Return whether the given point is inside the patch.
 |
 |      Parameters
 |      ----------
 |      point : (float, float)
 |          The point (x, y) to check, in target coordinates of
 |          ``self.get_transform()``. These are display coordinates for patches
 |          that are added to a figure or axes.
 |      radius : float, optional
 |          Add an additional margin on the patch in target coordinates of
 |          ``self.get_transform()``. See `.Path.contains_point` for further
 |          details.
 |
 |      Returns
 |      -------
 |      bool
 |
 |      Notes
 |      -----
 |      The proper use of this method depends on the transform of the patch.
 |      Isolated patches do not have a transform. In this case, the patch
 |      creation coordinates and the point coordinates match. The following
 |      example checks that the center of a circle is within the circle
 |
 |      >>> center = 0, 0
 |      >>> c = Circle(center, radius=1)
 |      >>> c.contains_point(center)
 |      True
 |
 |      The convention of checking against the transformed patch stems from
 |      the fact that this method is predominantly used to check if display
 |      coordinates (e.g. from mouse events) are within the patch. If you want
 |      to do the above check with data coordinates, you have to properly
 |      transform them first:
 |
 |      >>> center = 0, 0
 |      >>> c = Circle(center, radius=1)
 |      >>> plt.gca().add_patch(c)
 |      >>> transformed_center = c.get_transform().transform(center)
 |      >>> c.contains_point(transformed_center)
 |      True
 |
 |  contains_points(self, points, radius=None)
 |      Return whether the given points are inside the patch.
 |
 |      Parameters
 |      ----------
 |      points : (N, 2) array
 |          The points to check, in target coordinates of
 |          ``self.get_transform()``. These are display coordinates for patches
 |          that are added to a figure or axes. Columns contain x and y values.
 |      radius : float, optional
 |          Add an additional margin on the patch in target coordinates of
 |          ``self.get_transform()``. See `.Path.contains_point` for further
 |          details.
 |
 |      Returns
 |      -------
 |      length-N bool array
 |
 |      Notes
 |      -----
 |      The proper use of this method depends on the transform of the patch.
 |      See the notes on `.Patch.contains_point`.
 |
 |  draw(self, renderer)
 |      Draw the Artist (and its children) using the given renderer.
 |
 |      This has no effect if the artist is not visible (`.Artist.get_visible`
 |      returns False).
 |
 |      Parameters
 |      ----------
 |      renderer : `.RendererBase` subclass.
 |
 |      Notes
 |      -----
 |      This method is overridden in the Artist subclasses.
 |
 |  get_aa(self)
 |      Alias for `get_antialiased`.
 |
 |  get_antialiased(self)
 |      Return whether antialiasing is used for drawing.
 |
 |  get_capstyle(self)
 |      Return the capstyle.
 |
 |  get_data_transform(self)
 |      Return the `~.transforms.Transform` mapping data coordinates to
 |      physical coordinates.
 |
 |  get_ec(self)
 |      Alias for `get_edgecolor`.
 |
 |  get_edgecolor(self)
 |      Return the edge color.
 |
 |  get_extents(self)
 |      Return the `Patch`'s axis-aligned extents as a `~.transforms.Bbox`.
 |
 |  get_facecolor(self)
 |      Return the face color.
 |
 |  get_fc(self)
 |      Alias for `get_facecolor`.
 |
 |  get_fill(self)
 |      Return whether the patch is filled.
 |
 |  get_hatch(self)
 |      Return the hatching pattern.
 |
 |  get_joinstyle(self)
 |      Return the joinstyle.
 |
 |  get_linestyle(self)
 |      Return the linestyle.
 |
 |  get_linewidth(self)
 |      Return the line width in points.
 |
 |  get_ls(self)
 |      Alias for `get_linestyle`.
 |
 |  get_lw(self)
 |      Alias for `get_linewidth`.
 |
 |  get_transform(self)
 |      Return the `~.transforms.Transform` applied to the `Patch`.
 |
 |  get_verts(self)
 |      Return a copy of the vertices used in this patch.
 |
 |      If the patch contains Bezier curves, the curves will be interpolated by
 |      line segments.  To access the curves as curves, use `get_path`.
 |
 |  get_window_extent(self, renderer=None)
 |      Get the axes bounding box in display space.
 |
 |      The bounding box' width and height are nonnegative.
 |
 |      Subclasses should override for inclusion in the bounding box
 |      "tight" calculation. Default is to return an empty bounding
 |      box at 0, 0.
 |
 |      Be careful when using this function, the results will not update
 |      if the artist window extent of the artist changes.  The extent
 |      can change due to any changes in the transform stack, such as
 |      changing the axes limits, the figure size, or the canvas used
 |      (as is done when saving a figure).  This can lead to unexpected
 |      behavior where interactive figures will look fine on the screen,
 |      but will save incorrectly.
 |
 |  set_aa(self, aa)
 |      Alias for `set_antialiased`.
 |
 |  set_alpha(self, alpha)
 |      Set the alpha value used for blending - not supported on all backends.
 |
 |      Parameters
 |      ----------
 |      alpha : float or None
 |
 |  set_antialiased(self, aa)
 |      Set whether to use antialiased rendering.
 |
 |      Parameters
 |      ----------
 |      b : bool or None
 |
 |  set_capstyle(self, s)
 |      Set the capstyle.
 |
 |      Parameters
 |      ----------
 |      s : {'butt', 'round', 'projecting'}
 |
 |  set_color(self, c)
 |      Set both the edgecolor and the facecolor.
 |
 |      Parameters
 |      ----------
 |      c : color
 |
 |      See Also
 |      --------
 |      Patch.set_facecolor, Patch.set_edgecolor
 |          For setting the edge or face color individually.
 |
 |  set_ec(self, color)
 |      Alias for `set_edgecolor`.
 |
 |  set_edgecolor(self, color)
 |      Set the patch edge color.
 |
 |      Parameters
 |      ----------
 |      color : color or None or 'auto'
 |
 |  set_facecolor(self, color)
 |      Set the patch face color.
 |
 |      Parameters
 |      ----------
 |      color : color or None
 |
 |  set_fc(self, color)
 |      Alias for `set_facecolor`.
 |
 |  set_fill(self, b)
 |      Set whether to fill the patch.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_hatch(self, hatch)
 |      Set the hatching pattern.
 |
 |      *hatch* can be one of::
 |
 |        /   - diagonal hatching
 |        \   - back diagonal
 |        |   - vertical
 |        -   - horizontal
 |        +   - crossed
 |        x   - crossed diagonal
 |        o   - small circle
 |        O   - large circle
 |        .   - dots
 |        *   - stars
 |
 |      Letters can be combined, in which case all the specified
 |      hatchings are done.  If same letter repeats, it increases the
 |      density of hatching of that pattern.
 |
 |      Hatching is supported in the PostScript, PDF, SVG and Agg
 |      backends only.
 |
 |      Parameters
 |      ----------
 |      hatch : {'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
 |
 |  set_joinstyle(self, s)
 |      Set the joinstyle.
 |
 |      Parameters
 |      ----------
 |      s : {'miter', 'round', 'bevel'}
 |
 |  set_linestyle(self, ls)
 |      Set the patch linestyle.
 |
 |      ===========================   =================
 |      linestyle                     description
 |      ===========================   =================
 |      ``'-'`` or ``'solid'``        solid line
 |      ``'--'`` or  ``'dashed'``     dashed line
 |      ``'-.'`` or  ``'dashdot'``    dash-dotted line
 |      ``':'`` or ``'dotted'``       dotted line
 |      ===========================   =================
 |
 |      Alternatively a dash tuple of the following form can be provided::
 |
 |          (offset, onoffseq)
 |
 |      where ``onoffseq`` is an even length tuple of on and off ink in points.
 |
 |      Parameters
 |      ----------
 |      ls : {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
 |          The line style.
 |
 |  set_linewidth(self, w)
 |      Set the patch linewidth in points.
 |
 |      Parameters
 |      ----------
 |      w : float or None
 |
 |  set_ls(self, ls)
 |      Alias for `set_linestyle`.
 |
 |  set_lw(self, w)
 |      Alias for `set_linewidth`.
 |
 |  update_from(self, other)
 |      Copy properties from *other* to *self*.
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from Patch:
 |
 |  fill
 |      Return whether the patch is filled.
 |
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from Patch:
 |
 |  validCap = ('butt', 'round', 'projecting')
 |
 |  validJoin = ('miter', 'round', 'bevel')
 |
 |  zorder = 1
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from matplotlib.artist.Artist:
 |
 |  __getstate__(self)
 |
 |  add_callback(self, func)
 |      Add a callback function that will be called whenever one of the
 |      `.Artist`'s properties changes.
 |
 |      Parameters
 |      ----------
 |      func : callable
 |          The callback function. It must have the signature::
 |
 |              def func(artist: Artist) -> Any
 |
 |          where *artist* is the calling `.Artist`. Return values may exist
 |          but are ignored.
 |
 |      Returns
 |      -------
 |      int
 |          The observer id associated with the callback. This id can be
 |          used for removing the callback with `.remove_callback` later.
 |
 |      See Also
 |      --------
 |      remove_callback
 |
 |  convert_xunits(self, x)
 |      Convert *x* using the unit type of the xaxis.
 |
 |      If the artist is not in contained in an Axes or if the xaxis does not
 |      have units, *x* itself is returned.
 |
 |  convert_yunits(self, y)
 |      Convert *y* using the unit type of the yaxis.
 |
 |      If the artist is not in contained in an Axes or if the yaxis does not
 |      have units, *y* itself is returned.
 |
 |  findobj(self, match=None, include_self=True)
 |      Find artist objects.
 |
 |      Recursively find all `.Artist` instances contained in the artist.
 |
 |      Parameters
 |      ----------
 |      match
 |          A filter criterion for the matches. This can be
 |
 |          - *None*: Return all objects contained in artist.
 |          - A function with signature ``def match(artist: Artist) -> bool``.
 |            The result will only contain artists for which the function
 |            returns *True*.
 |          - A class instance: e.g., `.Line2D`. The result will only contain
 |            artists of this class or its subclasses (``isinstance`` check).
 |
 |      include_self : bool
 |          Include *self* in the list to be checked for a match.
 |
 |      Returns
 |      -------
 |      list of `.Artist`
 |
 |  format_cursor_data(self, data)
 |      Return a string representation of *data*.
 |
 |      .. note::
 |          This method is intended to be overridden by artist subclasses.
 |          As an end-user of Matplotlib you will most likely not call this
 |          method yourself.
 |
 |      The default implementation converts ints and floats and arrays of ints
 |      and floats into a comma-separated string enclosed in square brackets.
 |
 |      See Also
 |      --------
 |      get_cursor_data
 |
 |  get_agg_filter(self)
 |      Return filter function to be used for agg filter.
 |
 |  get_alpha(self)
 |      Return the alpha value used for blending - not supported on all
 |      backends.
 |
 |  get_animated(self)
 |      Return whether the artist is animated.
 |
 |  get_children(self)
 |      Return a list of the child `.Artist`\s of this `.Artist`.
 |
 |  get_clip_box(self)
 |      Return the clipbox.
 |
 |  get_clip_on(self)
 |      Return whether the artist uses clipping.
 |
 |  get_clip_path(self)
 |      Return the clip path.
 |
 |  get_contains(self)
 |      [*Deprecated*] Return the custom contains function of the artist if set, or *None*.
 |
 |      See Also
 |      --------
 |      set_contains
 |
 |      Notes
 |      -----
 |      .. deprecated:: 3.3
 |
 |  get_cursor_data(self, event)
 |      Return the cursor data for a given event.
 |
 |      .. note::
 |          This method is intended to be overridden by artist subclasses.
 |          As an end-user of Matplotlib you will most likely not call this
 |          method yourself.
 |
 |      Cursor data can be used by Artists to provide additional context
 |      information for a given event. The default implementation just returns
 |      *None*.
 |
 |      Subclasses can override the method and return arbitrary data. However,
 |      when doing so, they must ensure that `.format_cursor_data` can convert
 |      the data to a string representation.
 |
 |      The only current use case is displaying the z-value of an `.AxesImage`
 |      in the status bar of a plot window, while moving the mouse.
 |
 |      Parameters
 |      ----------
 |      event : `matplotlib.backend_bases.MouseEvent`
 |
 |      See Also
 |      --------
 |      format_cursor_data
 |
 |  get_figure(self)
 |      Return the `.Figure` instance the artist belongs to.
 |
 |  get_gid(self)
 |      Return the group id.
 |
 |  get_in_layout(self)
 |      Return boolean flag, ``True`` if artist is included in layout
 |      calculations.
 |
 |      E.g. :doc:`/tutorials/intermediate/constrainedlayout_guide`,
 |      `.Figure.tight_layout()`, and
 |      ``fig.savefig(fname, bbox_inches='tight')``.
 |
 |  get_label(self)
 |      Return the label used for this artist in the legend.
 |
 |  get_path_effects(self)
 |
 |  get_picker(self)
 |      Return the picking behavior of the artist.
 |
 |      The possible values are described in `.set_picker`.
 |
 |      See Also
 |      --------
 |      set_picker, pickable, pick
 |
 |  get_rasterized(self)
 |      Return whether the artist is to be rasterized.
 |
 |  get_sketch_params(self)
 |      Return the sketch parameters for the artist.
 |
 |      Returns
 |      -------
 |      tuple or None
 |
 |          A 3-tuple with the following elements:
 |
 |          - *scale*: The amplitude of the wiggle perpendicular to the
 |            source line.
 |          - *length*: The length of the wiggle along the line.
 |          - *randomness*: The scale factor by which the length is
 |            shrunken or expanded.
 |
 |          Returns *None* if no sketch parameters were set.
 |
 |  get_snap(self)
 |      Return the snap setting.
 |
 |      See `.set_snap` for details.
 |
 |  get_tightbbox(self, renderer)
 |      Like `.Artist.get_window_extent`, but includes any clipping.
 |
 |      Parameters
 |      ----------
 |      renderer : `.RendererBase` subclass
 |          renderer that will be used to draw the figures (i.e.
 |          ``fig.canvas.get_renderer()``)
 |
 |      Returns
 |      -------
 |      `.Bbox`
 |          The enclosing bounding box (in figure pixel coordinates).
 |
 |  get_transformed_clip_path_and_affine(self)
 |      Return the clip path with the non-affine part of its
 |      transformation applied, and the remaining affine part of its
 |      transformation.
 |
 |  get_url(self)
 |      Return the url.
 |
 |  get_visible(self)
 |      Return the visibility.
 |
 |  get_zorder(self)
 |      Return the artist's zorder.
 |
 |  have_units(self)
 |      Return *True* if units are set on any axis.
 |
 |  is_transform_set(self)
 |      Return whether the Artist has an explicitly set transform.
 |
 |      This is *True* after `.set_transform` has been called.
 |
 |  pchanged(self)
 |      Call all of the registered callbacks.
 |
 |      This function is triggered internally when a property is changed.
 |
 |      See Also
 |      --------
 |      add_callback
 |      remove_callback
 |
 |  pick(self, mouseevent)
 |      Process a pick event.
 |
 |      Each child artist will fire a pick event if *mouseevent* is over
 |      the artist and the artist has picker set.
 |
 |      See Also
 |      --------
 |      set_picker, get_picker, pickable
 |
 |  pickable(self)
 |      Return whether the artist is pickable.
 |
 |      See Also
 |      --------
 |      set_picker, get_picker, pick
 |
 |  properties(self)
 |      Return a dictionary of all the properties of the artist.
 |
 |  remove(self)
 |      Remove the artist from the figure if possible.
 |
 |      The effect will not be visible until the figure is redrawn, e.g.,
 |      with `.FigureCanvasBase.draw_idle`.  Call `~.axes.Axes.relim` to
 |      update the axes limits if desired.
 |
 |      Note: `~.axes.Axes.relim` will not see collections even if the
 |      collection was added to the axes with *autolim* = True.
 |
 |      Note: there is no support for removing the artist's legend entry.
 |
 |  remove_callback(self, oid)
 |      Remove a callback based on its observer id.
 |
 |      See Also
 |      --------
 |      add_callback
 |
 |  set(self, **kwargs)
 |      A property batch setter.  Pass *kwargs* to set properties.
 |
 |  set_agg_filter(self, filter_func)
 |      Set the agg filter.
 |
 |      Parameters
 |      ----------
 |      filter_func : callable
 |          A filter function, which takes a (m, n, 3) float array and a dpi
 |          value, and returns a (m, n, 3) array.
 |
 |          .. ACCEPTS: a filter function, which takes a (m, n, 3) float array
 |              and a dpi value, and returns a (m, n, 3) array
 |
 |  set_animated(self, b)
 |      Set the artist's animation state.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_clip_box(self, clipbox)
 |      Set the artist's clip `.Bbox`.
 |
 |      Parameters
 |      ----------
 |      clipbox : `.Bbox`
 |
 |  set_clip_on(self, b)
 |      Set whether the artist uses clipping.
 |
 |      When False artists will be visible outside of the axes which
 |      can lead to unexpected results.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_clip_path(self, path, transform=None)
 |      Set the artist's clip path.
 |
 |      Parameters
 |      ----------
 |      path : `.Patch` or `.Path` or `.TransformedPath` or None
 |          The clip path. If given a `.Path`, *transform* must be provided as
 |          well. If *None*, a previously set clip path is removed.
 |      transform : `~matplotlib.transforms.Transform`, optional
 |          Only used if *path* is a `.Path`, in which case the given `.Path`
 |          is converted to a `.TransformedPath` using *transform*.
 |
 |      Notes
 |      -----
 |      For efficiency, if *path* is a `.Rectangle` this method will set the
 |      clipping box to the corresponding rectangle and set the clipping path
 |      to ``None``.
 |
 |      For technical reasons (support of `~.Artist.set`), a tuple
 |      (*path*, *transform*) is also accepted as a single positional
 |      parameter.
 |
 |      .. ACCEPTS: Patch or (Path, Transform) or None
 |
 |  set_contains(self, picker)
 |      [*Deprecated*] Define a custom contains syntax for the artist.
 |
 |      The provided callable replaces the default `.contains` method
 |      of the artist.
 |
 |      Parameters
 |      ----------
 |      picker : callable
 |          A custom picker function to evaluate if an event is within the
 |          artist. The function must have the signature::
 |
 |              def contains(artist: Artist, event: MouseEvent) -> bool, dict
 |
 |          that returns:
 |
 |          - a bool indicating if the event is within the artist
 |          - a dict of additional information. The dict should at least
 |            return the same information as the default ``contains()``
 |            implementation of the respective artist, but may provide
 |            additional information.
 |
 |      Notes
 |      -----
 |      .. deprecated:: 3.3
 |
 |  set_figure(self, fig)
 |      Set the `.Figure` instance the artist belongs to.
 |
 |      Parameters
 |      ----------
 |      fig : `.Figure`
 |
 |  set_gid(self, gid)
 |      Set the (group) id for the artist.
 |
 |      Parameters
 |      ----------
 |      gid : str
 |
 |  set_in_layout(self, in_layout)
 |      Set if artist is to be included in layout calculations,
 |      E.g. :doc:`/tutorials/intermediate/constrainedlayout_guide`,
 |      `.Figure.tight_layout()`, and
 |      ``fig.savefig(fname, bbox_inches='tight')``.
 |
 |      Parameters
 |      ----------
 |      in_layout : bool
 |
 |  set_label(self, s)
 |      Set a label that will be displayed in the legend.
 |
 |      Parameters
 |      ----------
 |      s : object
 |          *s* will be converted to a string by calling `str`.
 |
 |  set_path_effects(self, path_effects)
 |      Set the path effects.
 |
 |      Parameters
 |      ----------
 |      path_effects : `.AbstractPathEffect`
 |
 |  set_picker(self, picker)
 |      Define the picking behavior of the artist.
 |
 |      Parameters
 |      ----------
 |      picker : None or bool or callable
 |          This can be one of the following:
 |
 |          - *None*: Picking is disabled for this artist (default).
 |
 |          - A boolean: If *True* then picking will be enabled and the
 |            artist will fire a pick event if the mouse event is over
 |            the artist.
 |
 |          - A function: If picker is callable, it is a user supplied
 |            function which determines whether the artist is hit by the
 |            mouse event::
 |
 |              hit, props = picker(artist, mouseevent)
 |
 |            to determine the hit syntax.  if the mouse event is over the
 |            artist, return *hit=True* and props is a dictionary of
 |            properties you want added to the PickEvent attributes.
 |
 |          - *deprecated*: For `.Line2D` only, *picker* can also be a float
 |            that sets the tolerance for checking whether an event occurred
 |            "on" the line; this is deprecated.  Use `.Line2D.set_pickradius`
 |            instead.
 |
 |  set_rasterized(self, rasterized)
 |      Force rasterized (bitmap) drawing in vector backend output.
 |
 |      Defaults to None, which implies the backend's default behavior.
 |
 |      Parameters
 |      ----------
 |      rasterized : bool or None
 |
 |  set_sketch_params(self, scale=None, length=None, randomness=None)
 |      Sets the sketch parameters.
 |
 |      Parameters
 |      ----------
 |      scale : float, optional
 |          The amplitude of the wiggle perpendicular to the source
 |          line, in pixels.  If scale is `None`, or not provided, no
 |          sketch filter will be provided.
 |      length : float, optional
 |           The length of the wiggle along the line, in pixels
 |           (default 128.0)
 |      randomness : float, optional
 |          The scale factor by which the length is shrunken or
 |          expanded (default 16.0)
 |
 |          .. ACCEPTS: (scale: float, length: float, randomness: float)
 |
 |  set_snap(self, snap)
 |      Set the snapping behavior.
 |
 |      Snapping aligns positions with the pixel grid, which results in
 |      clearer images. For example, if a black line of 1px width was
 |      defined at a position in between two pixels, the resulting image
 |      would contain the interpolated value of that line in the pixel grid,
 |      which would be a grey value on both adjacent pixel positions. In
 |      contrast, snapping will move the line to the nearest integer pixel
 |      value, so that the resulting image will really contain a 1px wide
 |      black line.
 |
 |      Snapping is currently only supported by the Agg and MacOSX backends.
 |
 |      Parameters
 |      ----------
 |      snap : bool or None
 |          Possible values:
 |
 |          - *True*: Snap vertices to the nearest pixel center.
 |          - *False*: Do not modify vertex positions.
 |          - *None*: (auto) If the path contains only rectilinear line
 |            segments, round to the nearest pixel center.
 |
 |  set_transform(self, t)
 |      Set the artist transform.
 |
 |      Parameters
 |      ----------
 |      t : `.Transform`
 |
 |  set_url(self, url)
 |      Set the url for the artist.
 |
 |      Parameters
 |      ----------
 |      url : str
 |
 |  set_visible(self, b)
 |      Set the artist's visibility.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_zorder(self, level)
 |      Set the zorder for the artist.  Artists with lower zorder
 |      values are drawn first.
 |
 |      Parameters
 |      ----------
 |      level : float
 |
 |  update(self, props)
 |      Update this artist's properties from the dict *props*.
 |
 |      Parameters
 |      ----------
 |      props : dict
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from matplotlib.artist.Artist:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)
 |
 |  axes
 |      The `~.axes.Axes` instance the artist resides in, or *None*.
 |
 |  mouseover
 |      If this property is set to *True*, the artist will be queried for
 |      custom context information when the mouse cursor moves over it.
 |
 |      See also :meth:`get_cursor_data`, :class:`.ToolCursorPosition` and
 |      :class:`.NavigationToolbar2`.
 |
 |  stale
 |      Whether the artist is 'stale' and needs to be re-drawn for the output
 |      to match the internal state of the artist.
 |
 |  sticky_edges
 |      ``x`` and ``y`` sticky edge lists for autoscaling.
 |
 |      When performing autoscaling, if a data limit coincides with a value in
 |      the corresponding sticky_edges list, then no margin will be added--the
 |      view limit "sticks" to the edge. A typical use case is histograms,
 |      where one usually expects no margin on the bottom edge (0) of the
 |      histogram.
 |
 |      This attribute cannot be assigned to; however, the ``x`` and ``y``
 |      lists can be modified in place as needed.
 |
 |      Examples
 |      --------
 |      >>> artist.sticky_edges.x[:] = (xmin, xmax)
 |      >>> artist.sticky_edges.y[:] = (ymin, ymax)

        """
        fig, ax = plt.subplots(subplot_kw={'aspect': 'equal'})
        ell_params = [dict(xy=(1, 3), width=2, height=0.5, angle=0, color='r', hatch='/'),
                      dict(xy=(2.5, 2), width=1.5, height=0.5, angle=10, color='b'),
                      dict(xy=(4, 1), width=1.5, height=1, angle=30, fill=False),
                      dict(xy=(5.5, 1), width=2, height=0.5, angle=120),
                      ]
        ells = [mpl.patches.Ellipse(**d) for d in ell_params]
        for j, (e, p) in enumerate(zip(ells, ell_params)):
            ax.add_artist(e)
            ax.annotate(
                text=str(p)[1:-1],
                xytext=(p['xy'][0], 4.5-j*0.8),
                xy=(p['xy'][0], p['xy'][1]+p['height']/2),
                arrowprops=dict(width=1),
                bbox=dict(color='lightgreen', alpha=0.3)
            )

        ax.set_xlim(0, 10)
        ax.set_ylim(0, 5)

    @staticmethod
    def arrow():
        """
class Arrow(Patch)
 |  Arrow(x, y, dx, dy, width=1.0, **kwargs)
 |
 |  An arrow patch.
 |
 |  Method resolution order:
 |      Arrow
 |      Patch
 |      matplotlib.artist.Artist
 |      builtins.object
 |
 |  Methods defined here:
 |
 |  __init__(self, x, y, dx, dy, width=1.0, **kwargs)
 |      Draws an arrow from (*x*, *y*) to (*x* + *dx*, *y* + *dy*).
 |      The width of the arrow is scaled by *width*.
 |
 |      Parameters
 |      ----------
 |      x : float
 |          x coordinate of the arrow tail.
 |      y : float
 |          y coordinate of the arrow tail.
 |      dx : float
 |          Arrow length in the x direction.
 |      dy : float
 |          Arrow length in the y direction.
 |      width : float, default: 1
 |          Scale factor for the width of the arrow. With a default value of 1,
 |          the tail width is 0.2 and head width is 0.6.
 |      **kwargs
 |          Keyword arguments control the `Patch` properties:
 |
 |          Properties:
 |          agg_filter: a filter function, which takes a (m, n, 3) float array and a dpi value, and returns a (m, n, 3) array
 |          alpha: float or None
 |          animated: bool
 |          antialiased or aa: unknown
 |          capstyle: {'butt', 'round', 'projecting'}
 |          clip_box: `.Bbox`
 |          clip_on: bool
 |          clip_path: Patch or (Path, Transform) or None
 |          color: color
 |          contains: unknown
 |          edgecolor or ec: color or None or 'auto'
 |          facecolor or fc: color or None
 |          figure: `.Figure`
 |          fill: bool
 |          gid: str
 |          hatch: {'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
 |          in_layout: bool
 |          joinstyle: {'miter', 'round', 'bevel'}
 |          label: object
 |          linestyle or ls: {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
 |          linewidth or lw: float or None
 |          path_effects: `.AbstractPathEffect`
 |          picker: None or bool or callable
 |          rasterized: bool or None
 |          sketch_params: (scale: float, length: float, randomness: float)
 |          snap: bool or None
 |          transform: `.Transform`
 |          url: str
 |          visible: bool
 |          zorder: float
 |
 |      See Also
 |      --------
 |      FancyArrow
 |          Patch that allows independent control of the head and tail
 |          properties.
 |
 |  __str__(self)
 |      Return str(self).
 |
 |  get_patch_transform(self)
 |      Return the `~.transforms.Transform` instance mapping patch coordinates
 |      to data coordinates.
 |
 |      For example, one may define a patch of a circle which represents a
 |      radius of 5 by providing coordinates for a unit circle, and a
 |      transform which scales the coordinates (the patch coordinate) by 5.
 |
 |  get_path(self)
 |      Return the path of this patch.
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from Patch:
 |
 |  contains(self, mouseevent, radius=None)
 |      Test whether the mouse event occurred in the patch.
 |
 |      Returns
 |      -------
 |      (bool, empty dict)
 |
 |  contains_point(self, point, radius=None)
 |      Return whether the given point is inside the patch.
 |
 |      Parameters
 |      ----------
 |      point : (float, float)
 |          The point (x, y) to check, in target coordinates of
 |          ``self.get_transform()``. These are display coordinates for patches
 |          that are added to a figure or axes.
 |      radius : float, optional
 |          Add an additional margin on the patch in target coordinates of
 |          ``self.get_transform()``. See `.Path.contains_point` for further
 |          details.
 |
 |      Returns
 |      -------
 |      bool
 |
 |      Notes
 |      -----
 |      The proper use of this method depends on the transform of the patch.
 |      Isolated patches do not have a transform. In this case, the patch
 |      creation coordinates and the point coordinates match. The following
 |      example checks that the center of a circle is within the circle
 |
 |      >>> center = 0, 0
 |      >>> c = Circle(center, radius=1)
 |      >>> c.contains_point(center)
 |      True
 |
 |      The convention of checking against the transformed patch stems from
 |      the fact that this method is predominantly used to check if display
 |      coordinates (e.g. from mouse events) are within the patch. If you want
 |      to do the above check with data coordinates, you have to properly
 |      transform them first:
 |
 |      >>> center = 0, 0
 |      >>> c = Circle(center, radius=1)
 |      >>> plt.gca().add_patch(c)
 |      >>> transformed_center = c.get_transform().transform(center)
 |      >>> c.contains_point(transformed_center)
 |      True
 |
 |  contains_points(self, points, radius=None)
 |      Return whether the given points are inside the patch.
 |
 |      Parameters
 |      ----------
 |      points : (N, 2) array
 |          The points to check, in target coordinates of
 |          ``self.get_transform()``. These are display coordinates for patches
 |          that are added to a figure or axes. Columns contain x and y values.
 |      radius : float, optional
 |          Add an additional margin on the patch in target coordinates of
 |          ``self.get_transform()``. See `.Path.contains_point` for further
 |          details.
 |
 |      Returns
 |      -------
 |      length-N bool array
 |
 |      Notes
 |      -----
 |      The proper use of this method depends on the transform of the patch.
 |      See the notes on `.Patch.contains_point`.
 |
 |  draw(self, renderer)
 |      Draw the Artist (and its children) using the given renderer.
 |
 |      This has no effect if the artist is not visible (`.Artist.get_visible`
 |      returns False).
 |
 |      Parameters
 |      ----------
 |      renderer : `.RendererBase` subclass.
 |
 |      Notes
 |      -----
 |      This method is overridden in the Artist subclasses.
 |
 |  get_aa(self)
 |      Alias for `get_antialiased`.
 |
 |  get_antialiased(self)
 |      Return whether antialiasing is used for drawing.
 |
 |  get_capstyle(self)
 |      Return the capstyle.
 |
 |  get_data_transform(self)
 |      Return the `~.transforms.Transform` mapping data coordinates to
 |      physical coordinates.
 |
 |  get_ec(self)
 |      Alias for `get_edgecolor`.
 |
 |  get_edgecolor(self)
 |      Return the edge color.
 |
 |  get_extents(self)
 |      Return the `Patch`'s axis-aligned extents as a `~.transforms.Bbox`.
 |
 |  get_facecolor(self)
 |      Return the face color.
 |
 |  get_fc(self)
 |      Alias for `get_facecolor`.
 |
 |  get_fill(self)
 |      Return whether the patch is filled.
 |
 |  get_hatch(self)
 |      Return the hatching pattern.
 |
 |  get_joinstyle(self)
 |      Return the joinstyle.
 |
 |  get_linestyle(self)
 |      Return the linestyle.
 |
 |  get_linewidth(self)
 |      Return the line width in points.
 |
 |  get_ls(self)
 |      Alias for `get_linestyle`.
 |
 |  get_lw(self)
 |      Alias for `get_linewidth`.
 |
 |  get_transform(self)
 |      Return the `~.transforms.Transform` applied to the `Patch`.
 |
 |  get_verts(self)
 |      Return a copy of the vertices used in this patch.
 |
 |      If the patch contains Bezier curves, the curves will be interpolated by
 |      line segments.  To access the curves as curves, use `get_path`.
 |
 |  get_window_extent(self, renderer=None)
 |      Get the axes bounding box in display space.
 |
 |      The bounding box' width and height are nonnegative.
 |
 |      Subclasses should override for inclusion in the bounding box
 |      "tight" calculation. Default is to return an empty bounding
 |      box at 0, 0.
 |
 |      Be careful when using this function, the results will not update
 |      if the artist window extent of the artist changes.  The extent
 |      can change due to any changes in the transform stack, such as
 |      changing the axes limits, the figure size, or the canvas used
 |      (as is done when saving a figure).  This can lead to unexpected
 |      behavior where interactive figures will look fine on the screen,
 |      but will save incorrectly.
 |
 |  set_aa(self, aa)
 |      Alias for `set_antialiased`.
 |
 |  set_alpha(self, alpha)
 |      Set the alpha value used for blending - not supported on all backends.
 |
 |      Parameters
 |      ----------
 |      alpha : float or None
 |
 |  set_antialiased(self, aa)
 |      Set whether to use antialiased rendering.
 |
 |      Parameters
 |      ----------
 |      b : bool or None
 |
 |  set_capstyle(self, s)
 |      Set the capstyle.
 |
 |      Parameters
 |      ----------
 |      s : {'butt', 'round', 'projecting'}
 |
 |  set_color(self, c)
 |      Set both the edgecolor and the facecolor.
 |
 |      Parameters
 |      ----------
 |      c : color
 |
 |      See Also
 |      --------
 |      Patch.set_facecolor, Patch.set_edgecolor
 |          For setting the edge or face color individually.
 |
 |  set_ec(self, color)
 |      Alias for `set_edgecolor`.
 |
 |  set_edgecolor(self, color)
 |      Set the patch edge color.
 |
 |      Parameters
 |      ----------
 |      color : color or None or 'auto'
 |
 |  set_facecolor(self, color)
 |      Set the patch face color.
 |
 |      Parameters
 |      ----------
 |      color : color or None
 |
 |  set_fc(self, color)
 |      Alias for `set_facecolor`.
 |
 |  set_fill(self, b)
 |      Set whether to fill the patch.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_hatch(self, hatch)
 |      Set the hatching pattern.
 |
 |      *hatch* can be one of::
 |
 |        /   - diagonal hatching
 |        \   - back diagonal
 |        |   - vertical
 |        -   - horizontal
 |        +   - crossed
 |        x   - crossed diagonal
 |        o   - small circle
 |        O   - large circle
 |        .   - dots
 |        *   - stars
 |
 |      Letters can be combined, in which case all the specified
 |      hatchings are done.  If same letter repeats, it increases the
 |      density of hatching of that pattern.
 |
 |      Hatching is supported in the PostScript, PDF, SVG and Agg
 |      backends only.
 |
 |      Parameters
 |      ----------
 |      hatch : {'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
 |
 |  set_joinstyle(self, s)
 |      Set the joinstyle.
 |
 |      Parameters
 |      ----------
 |      s : {'miter', 'round', 'bevel'}
 |
 |  set_linestyle(self, ls)
 |      Set the patch linestyle.
 |
 |      ===========================   =================
 |      linestyle                     description
 |      ===========================   =================
 |      ``'-'`` or ``'solid'``        solid line
 |      ``'--'`` or  ``'dashed'``     dashed line
 |      ``'-.'`` or  ``'dashdot'``    dash-dotted line
 |      ``':'`` or ``'dotted'``       dotted line
 |      ===========================   =================
 |
 |      Alternatively a dash tuple of the following form can be provided::
 |
 |          (offset, onoffseq)
 |
 |      where ``onoffseq`` is an even length tuple of on and off ink in points.
 |
 |      Parameters
 |      ----------
 |      ls : {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
 |          The line style.
 |
 |  set_linewidth(self, w)
 |      Set the patch linewidth in points.
 |
 |      Parameters
 |      ----------
 |      w : float or None
 |
 |  set_ls(self, ls)
 |      Alias for `set_linestyle`.
 |
 |  set_lw(self, w)
 |      Alias for `set_linewidth`.
 |
 |  update_from(self, other)
 |      Copy properties from *other* to *self*.
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from Patch:
 |
 |  fill
 |      Return whether the patch is filled.
 |
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from Patch:
 |
 |  validCap = ('butt', 'round', 'projecting')
 |
 |  validJoin = ('miter', 'round', 'bevel')
 |
 |  zorder = 1
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from matplotlib.artist.Artist:
 |
 |  __getstate__(self)
 |
 |  add_callback(self, func)
 |      Add a callback function that will be called whenever one of the
 |      `.Artist`'s properties changes.
 |
 |      Parameters
 |      ----------
 |      func : callable
 |          The callback function. It must have the signature::
 |
 |              def func(artist: Artist) -> Any
 |
 |          where *artist* is the calling `.Artist`. Return values may exist
 |          but are ignored.
 |
 |      Returns
 |      -------
 |      int
 |          The observer id associated with the callback. This id can be
 |          used for removing the callback with `.remove_callback` later.
 |
 |      See Also
 |      --------
 |      remove_callback
 |
 |  convert_xunits(self, x)
 |      Convert *x* using the unit type of the xaxis.
 |
 |      If the artist is not in contained in an Axes or if the xaxis does not
 |      have units, *x* itself is returned.
 |
 |  convert_yunits(self, y)
 |      Convert *y* using the unit type of the yaxis.
 |
 |      If the artist is not in contained in an Axes or if the yaxis does not
 |      have units, *y* itself is returned.
 |
 |  findobj(self, match=None, include_self=True)
 |      Find artist objects.
 |
 |      Recursively find all `.Artist` instances contained in the artist.
 |
 |      Parameters
 |      ----------
 |      match
 |          A filter criterion for the matches. This can be
 |
 |          - *None*: Return all objects contained in artist.
 |          - A function with signature ``def match(artist: Artist) -> bool``.
 |            The result will only contain artists for which the function
 |            returns *True*.
 |          - A class instance: e.g., `.Line2D`. The result will only contain
 |            artists of this class or its subclasses (``isinstance`` check).
 |
 |      include_self : bool
 |          Include *self* in the list to be checked for a match.
 |
 |      Returns
 |      -------
 |      list of `.Artist`
 |
 |  format_cursor_data(self, data)
 |      Return a string representation of *data*.
 |
 |      .. note::
 |          This method is intended to be overridden by artist subclasses.
 |          As an end-user of Matplotlib you will most likely not call this
 |          method yourself.
 |
 |      The default implementation converts ints and floats and arrays of ints
 |      and floats into a comma-separated string enclosed in square brackets.
 |
 |      See Also
 |      --------
 |      get_cursor_data
 |
 |  get_agg_filter(self)
 |      Return filter function to be used for agg filter.
 |
 |  get_alpha(self)
 |      Return the alpha value used for blending - not supported on all
 |      backends.
 |
 |  get_animated(self)
 |      Return whether the artist is animated.
 |
 |  get_children(self)
 |      Return a list of the child `.Artist`\s of this `.Artist`.
 |
 |  get_clip_box(self)
 |      Return the clipbox.
 |
 |  get_clip_on(self)
 |      Return whether the artist uses clipping.
 |
 |  get_clip_path(self)
 |      Return the clip path.
 |
 |  get_contains(self)
 |      [*Deprecated*] Return the custom contains function of the artist if set, or *None*.
 |
 |      See Also
 |      --------
 |      set_contains
 |
 |      Notes
 |      -----
 |      .. deprecated:: 3.3
 |
 |  get_cursor_data(self, event)
 |      Return the cursor data for a given event.
 |
 |      .. note::
 |          This method is intended to be overridden by artist subclasses.
 |          As an end-user of Matplotlib you will most likely not call this
 |          method yourself.
 |
 |      Cursor data can be used by Artists to provide additional context
 |      information for a given event. The default implementation just returns
 |      *None*.
 |
 |      Subclasses can override the method and return arbitrary data. However,
 |      when doing so, they must ensure that `.format_cursor_data` can convert
 |      the data to a string representation.
 |
 |      The only current use case is displaying the z-value of an `.AxesImage`
 |      in the status bar of a plot window, while moving the mouse.
 |
 |      Parameters
 |      ----------
 |      event : `matplotlib.backend_bases.MouseEvent`
 |
 |      See Also
 |      --------
 |      format_cursor_data
 |
 |  get_figure(self)
 |      Return the `.Figure` instance the artist belongs to.
 |
 |  get_gid(self)
 |      Return the group id.
 |
 |  get_in_layout(self)
 |      Return boolean flag, ``True`` if artist is included in layout
 |      calculations.
 |
 |      E.g. :doc:`/tutorials/intermediate/constrainedlayout_guide`,
 |      `.Figure.tight_layout()`, and
 |      ``fig.savefig(fname, bbox_inches='tight')``.
 |
 |  get_label(self)
 |      Return the label used for this artist in the legend.
 |
 |  get_path_effects(self)
 |
 |  get_picker(self)
 |      Return the picking behavior of the artist.
 |
 |      The possible values are described in `.set_picker`.
 |
 |      See Also
 |      --------
 |      set_picker, pickable, pick
 |
 |  get_rasterized(self)
 |      Return whether the artist is to be rasterized.
 |
 |  get_sketch_params(self)
 |      Return the sketch parameters for the artist.
 |
 |      Returns
 |      -------
 |      tuple or None
 |
 |          A 3-tuple with the following elements:
 |
 |          - *scale*: The amplitude of the wiggle perpendicular to the
 |            source line.
 |          - *length*: The length of the wiggle along the line.
 |          - *randomness*: The scale factor by which the length is
 |            shrunken or expanded.
 |
 |          Returns *None* if no sketch parameters were set.
 |
 |  get_snap(self)
 |      Return the snap setting.
 |
 |      See `.set_snap` for details.
 |
 |  get_tightbbox(self, renderer)
 |      Like `.Artist.get_window_extent`, but includes any clipping.
 |
 |      Parameters
 |      ----------
 |      renderer : `.RendererBase` subclass
 |          renderer that will be used to draw the figures (i.e.
 |          ``fig.canvas.get_renderer()``)
 |
 |      Returns
 |      -------
 |      `.Bbox`
 |          The enclosing bounding box (in figure pixel coordinates).
 |
 |  get_transformed_clip_path_and_affine(self)
 |      Return the clip path with the non-affine part of its
 |      transformation applied, and the remaining affine part of its
 |      transformation.
 |
 |  get_url(self)
 |      Return the url.
 |
 |  get_visible(self)
 |      Return the visibility.
 |
 |  get_zorder(self)
 |      Return the artist's zorder.
 |
 |  have_units(self)
 |      Return *True* if units are set on any axis.
 |
 |  is_transform_set(self)
 |      Return whether the Artist has an explicitly set transform.
 |
 |      This is *True* after `.set_transform` has been called.
 |
 |  pchanged(self)
 |      Call all of the registered callbacks.
 |
 |      This function is triggered internally when a property is changed.
 |
 |      See Also
 |      --------
 |      add_callback
 |      remove_callback
 |
 |  pick(self, mouseevent)
 |      Process a pick event.
 |
 |      Each child artist will fire a pick event if *mouseevent* is over
 |      the artist and the artist has picker set.
 |
 |      See Also
 |      --------
 |      set_picker, get_picker, pickable
 |
 |  pickable(self)
 |      Return whether the artist is pickable.
 |
 |      See Also
 |      --------
 |      set_picker, get_picker, pick
 |
 |  properties(self)
 |      Return a dictionary of all the properties of the artist.
 |
 |  remove(self)
 |      Remove the artist from the figure if possible.
 |
 |      The effect will not be visible until the figure is redrawn, e.g.,
 |      with `.FigureCanvasBase.draw_idle`.  Call `~.axes.Axes.relim` to
 |      update the axes limits if desired.
 |
 |      Note: `~.axes.Axes.relim` will not see collections even if the
 |      collection was added to the axes with *autolim* = True.
 |
 |      Note: there is no support for removing the artist's legend entry.
 |
 |  remove_callback(self, oid)
 |      Remove a callback based on its observer id.
 |
 |      See Also
 |      --------
 |      add_callback
 |
 |  set(self, **kwargs)
 |      A property batch setter.  Pass *kwargs* to set properties.
 |
 |  set_agg_filter(self, filter_func)
 |      Set the agg filter.
 |
 |      Parameters
 |      ----------
 |      filter_func : callable
 |          A filter function, which takes a (m, n, 3) float array and a dpi
 |          value, and returns a (m, n, 3) array.
 |
 |          .. ACCEPTS: a filter function, which takes a (m, n, 3) float array
 |              and a dpi value, and returns a (m, n, 3) array
 |
 |  set_animated(self, b)
 |      Set the artist's animation state.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_clip_box(self, clipbox)
 |      Set the artist's clip `.Bbox`.
 |
 |      Parameters
 |      ----------
 |      clipbox : `.Bbox`
 |
 |  set_clip_on(self, b)
 |      Set whether the artist uses clipping.
 |
 |      When False artists will be visible outside of the axes which
 |      can lead to unexpected results.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_clip_path(self, path, transform=None)
 |      Set the artist's clip path.
 |
 |      Parameters
 |      ----------
 |      path : `.Patch` or `.Path` or `.TransformedPath` or None
 |          The clip path. If given a `.Path`, *transform* must be provided as
 |          well. If *None*, a previously set clip path is removed.
 |      transform : `~matplotlib.transforms.Transform`, optional
 |          Only used if *path* is a `.Path`, in which case the given `.Path`
 |          is converted to a `.TransformedPath` using *transform*.
 |
 |      Notes
 |      -----
 |      For efficiency, if *path* is a `.Rectangle` this method will set the
 |      clipping box to the corresponding rectangle and set the clipping path
 |      to ``None``.
 |
 |      For technical reasons (support of `~.Artist.set`), a tuple
 |      (*path*, *transform*) is also accepted as a single positional
 |      parameter.
 |
 |      .. ACCEPTS: Patch or (Path, Transform) or None
 |
 |  set_contains(self, picker)
 |      [*Deprecated*] Define a custom contains syntax for the artist.
 |
 |      The provided callable replaces the default `.contains` method
 |      of the artist.
 |
 |      Parameters
 |      ----------
 |      picker : callable
 |          A custom picker function to evaluate if an event is within the
 |          artist. The function must have the signature::
 |
 |              def contains(artist: Artist, event: MouseEvent) -> bool, dict
 |
 |          that returns:
 |
 |          - a bool indicating if the event is within the artist
 |          - a dict of additional information. The dict should at least
 |            return the same information as the default ``contains()``
 |            implementation of the respective artist, but may provide
 |            additional information.
 |
 |      Notes
 |      -----
 |      .. deprecated:: 3.3
 |
 |  set_figure(self, fig)
 |      Set the `.Figure` instance the artist belongs to.
 |
 |      Parameters
 |      ----------
 |      fig : `.Figure`
 |
 |  set_gid(self, gid)
 |      Set the (group) id for the artist.
 |              """
        patches = DemoPatch.patches

        fig, axs = plt.subplots(nrows=3, ncols=2)

        x_tail, y_tail = 0.1, 0.1
        x_head, y_head = 0.85, 0.85
        dx = x_head - x_tail
        dy = y_head - y_tail
        alpha = 0.4

        # Arrow11
        arrow11 = patches.Arrow(x_tail, y_tail, dx=dx, dy=dy, alpha=alpha)
        axs[0, 0].add_patch(arrow11)
        axs[0, 0].text(x=0.4, y=0.1,
                       s='x={}, y={}, dx={}, dy={}, alpha={}'.format(x_tail, y_tail, dx, dy, alpha),
                       bbox=dict(facecolor='y', edgecolor='b', linewidth=1, alpha=0.3)
                       )
        axs[0, 0].scatter(x=(x_tail, x_head), y=(y_tail, y_head), c='r', s=50)
        axs[0, 0].annotate(xytext=(0.2, 0.6), text='tail:({}, {})'.format(x_tail, y_tail),
                           xy=(x_tail, y_tail),
                           arrowprops=dict(arrowstyle='->',
                                           connectionstyle='angle, angleA=0, angleB=90, rad=10'),
                           bbox=dict(boxstyle='round', facecolor='lightgreen')
                           )
        axs[0, 0].annotate(xytext=(0.2, 0.72), text='head:({}, {})'.format(x_head, y_head),
                           xy=(x_head, y_head),
                           arrowprops=dict(arrowstyle='->',
                                           connectionstyle='angle, angleA=-10, angleB=90, rad=50'),
                           bbox=dict(boxstyle='round', facecolor='lightgreen')
                           )
        # use negtive dx
        x1_tail, y1_tail, dx1, dy1 = 0.5, 0.5, -0.2, 0.75
        arrow12 = patches.Arrow(x1_tail, y1_tail, dx=dx1, dy=dy1, alpha=alpha)
        axs[1, 0].add_patch(arrow12)
        axs[1, 0].scatter(x=(x1_tail, x1_tail+dx), y=(y1_tail, y1_tail+dy), c='r', s=50)
        axs[1, 0].set(xlim=(0, 1), ylim=(0, 1.5))

        # mutate scale
        arrow13 = patches.Arrow(x_tail, y_tail, dx=dx, dy=dy, alpha=alpha,
                                transform=axs[2, 0].transAxes)
        axs[2, 0].add_patch(arrow13)
        axs[2, 0].scatter(x=(x_tail, x_head), y=(y_tail, y_head), c='r', s=50)

        # FancyArrowPatch
        arrow21 = patches.FancyArrowPatch(
            (x_tail, y_tail), (x_head, y_head), mutation_scale=100)
        axs[0, 1].add_patch(arrow21)
        arrow22 = patches.FancyArrowPatch(
            (x_tail, y_tail), (x_head, y_head), mutation_scale=100)
        axs[1, 1].add_patch(arrow22)
        arrow23 = patches.FancyArrowPatch(
            (x_tail, y_tail), (x_head, y_head), mutation_scale=100, transform=axs[2, 1].transAxes)
        axs[2, 1].add_patch(arrow23)

        axs[1, 1].set(xlim=(0, 2), ylim=(0, 2))
        axs[2, 0].set(xlim=(0, 2), ylim=(0, 2))
        axs[2, 1].set(xlim=(0, 2), ylim=(0, 2))

    @staticmethod
    def wedge():
        """
class Wedge(Patch)
 |  Wedge(center, r, theta1, theta2, width=None, **kwargs)
 |
 |  Wedge shaped patch.
 |
 |  Method resolution order:
 |      Wedge
 |      Patch
 |      matplotlib.artist.Artist
 |      builtins.object
 |
 |  Methods defined here:
 |
 |  __init__(self, center, r, theta1, theta2, width=None, **kwargs)
 |      A wedge centered at *x*, *y* center with radius *r* that
 |      sweeps *theta1* to *theta2* (in degrees).  If *width* is given,
 |      then a partial wedge is drawn from inner radius *r* - *width*
 |      to outer radius *r*.
 |
 |      Valid keyword arguments are:
 |
 |      Properties:
 |          agg_filter: a filter function, which takes a (m, n, 3) float array and a dpi value, and returns a (m, n, 3) array
 |          alpha: float or None
 |          animated: bool
 |          antialiased or aa: unknown
 |          capstyle: {'butt', 'round', 'projecting'}
 |          clip_box: `.Bbox`
 |          clip_on: bool
 |          clip_path: Patch or (Path, Transform) or None
 |          color: color
 |          contains: unknown
 |          edgecolor or ec: color or None or 'auto'
 |          facecolor or fc: color or None
 |          figure: `.Figure`
 |          fill: bool
 |          gid: str
 |          hatch: {'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
 |          in_layout: bool
 |          joinstyle: {'miter', 'round', 'bevel'}
 |          label: object
 |          linestyle or ls: {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
 |          linewidth or lw: float or None
 |          path_effects: `.AbstractPathEffect`
 |          picker: None or bool or callable
 |          rasterized: bool or None
 |          sketch_params: (scale: float, length: float, randomness: float)
 |          snap: bool or None
 |          transform: `.Transform`
 |          url: str
 |          visible: bool
 |          zorder: float
 |
 |  __str__(self)
 |      Return str(self).
 |
 |  get_path(self)
 |      Return the path of this patch.
 |
 |  set_center(self, center)
 |
 |  set_radius(self, radius)
 |
 |  set_theta1(self, theta1)
 |
 |  set_theta2(self, theta2)
 |
 |  set_width(self, width)
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from Patch:
 |
 |  contains(self, mouseevent, radius=None)
 |      Test whether the mouse event occurred in the patch.
 |
 |      Returns
 |      -------
 |      (bool, empty dict)
 |
 |  contains_point(self, point, radius=None)
 |      Return whether the given point is inside the patch.
 |
 |      Parameters
 |      ----------
 |      point : (float, float)
 |          The point (x, y) to check, in target coordinates of
 |          ``self.get_transform()``. These are display coordinates for patches
 |          that are added to a figure or axes.
 |      radius : float, optional
 |          Add an additional margin on the patch in target coordinates of
 |          ``self.get_transform()``. See `.Path.contains_point` for further
 |          details.
 |
 |      Returns
 |      -------
 |      bool
 |
 |      Notes
 |      -----
 |      The proper use of this method depends on the transform of the patch.
 |      Isolated patches do not have a transform. In this case, the patch
 |      creation coordinates and the point coordinates match. The following
 |      example checks that the center of a circle is within the circle
 |
 |      >>> center = 0, 0
 |      >>> c = Circle(center, radius=1)
 |      >>> c.contains_point(center)
 |      True
 |
 |      The convention of checking against the transformed patch stems from
 |      the fact that this method is predominantly used to check if display
 |      coordinates (e.g. from mouse events) are within the patch. If you want
 |      to do the above check with data coordinates, you have to properly
 |      transform them first:
 |
 |      >>> center = 0, 0
 |      >>> c = Circle(center, radius=1)
 |      >>> plt.gca().add_patch(c)
 |      >>> transformed_center = c.get_transform().transform(center)
 |      >>> c.contains_point(transformed_center)
 |      True
 |
 |  contains_points(self, points, radius=None)
 |      Return whether the given points are inside the patch.
 |
 |      Parameters
 |      ----------
 |      points : (N, 2) array
 |          The points to check, in target coordinates of
 |          ``self.get_transform()``. These are display coordinates for patches
 |          that are added to a figure or axes. Columns contain x and y values.
 |      radius : float, optional
 |          Add an additional margin on the patch in target coordinates of
 |          ``self.get_transform()``. See `.Path.contains_point` for further
 |          details.
 |
 |      Returns
 |      -------
 |      length-N bool array
 |
 |      Notes
 |      -----
 |      The proper use of this method depends on the transform of the patch.
 |      See the notes on `.Patch.contains_point`.
 |
 |  draw(self, renderer)
 |      Draw the Artist (and its children) using the given renderer.
 |
 |      This has no effect if the artist is not visible (`.Artist.get_visible`
 |      returns False).
 |
 |      Parameters
 |      ----------
 |      renderer : `.RendererBase` subclass.
 |
 |      Notes
 |      -----
 |      This method is overridden in the Artist subclasses.
 |
 |  get_aa(self)
 |      Alias for `get_antialiased`.
 |
 |  get_antialiased(self)
 |      Return whether antialiasing is used for drawing.
 |
 |  get_capstyle(self)
 |      Return the capstyle.
 |
 |  get_data_transform(self)
 |      Return the `~.transforms.Transform` mapping data coordinates to
 |      physical coordinates.
 |
 |  get_ec(self)
 |      Alias for `get_edgecolor`.
 |
 |  get_edgecolor(self)
 |      Return the edge color.
 |
 |  get_extents(self)
 |      Return the `Patch`'s axis-aligned extents as a `~.transforms.Bbox`.
 |
 |  get_facecolor(self)
 |      Return the face color.
 |
 |  get_fc(self)
 |      Alias for `get_facecolor`.
 |
 |  get_fill(self)
 |      Return whether the patch is filled.
 |
 |  get_hatch(self)
 |      Return the hatching pattern.
 |
 |  get_joinstyle(self)
 |      Return the joinstyle.
 |
 |  get_linestyle(self)
 |      Return the linestyle.
 |
 |  get_linewidth(self)
 |      Return the line width in points.
 |
 |  get_ls(self)
 |      Alias for `get_linestyle`.
 |
 |  get_lw(self)
 |      Alias for `get_linewidth`.
 |
 |  get_patch_transform(self)
 |      Return the `~.transforms.Transform` instance mapping patch coordinates
 |      to data coordinates.
 |
 |      For example, one may define a patch of a circle which represents a
 |      radius of 5 by providing coordinates for a unit circle, and a
 |      transform which scales the coordinates (the patch coordinate) by 5.
 |
 |  get_transform(self)
 |      Return the `~.transforms.Transform` applied to the `Patch`.
 |
 |  get_verts(self)
 |      Return a copy of the vertices used in this patch.
 |
 |      If the patch contains Bezier curves, the curves will be interpolated by
 |      line segments.  To access the curves as curves, use `get_path`.
 |
 |  get_window_extent(self, renderer=None)
 |      Get the axes bounding box in display space.
 |
 |      The bounding box' width and height are nonnegative.
 |
 |      Subclasses should override for inclusion in the bounding box
 |      "tight" calculation. Default is to return an empty bounding
 |      box at 0, 0.
 |
 |      Be careful when using this function, the results will not update
 |      if the artist window extent of the artist changes.  The extent
 |      can change due to any changes in the transform stack, such as
 |      changing the axes limits, the figure size, or the canvas used
 |      (as is done when saving a figure).  This can lead to unexpected
 |      behavior where interactive figures will look fine on the screen,
 |      but will save incorrectly.
 |
 |  set_aa(self, aa)
 |      Alias for `set_antialiased`.
 |
 |  set_alpha(self, alpha)
 |      Set the alpha value used for blending - not supported on all backends.
 |
 |      Parameters
 |      ----------
 |      alpha : float or None
 |
 |  set_antialiased(self, aa)
 |      Set whether to use antialiased rendering.
 |
 |      Parameters
 |      ----------
 |      b : bool or None
 |
 |  set_capstyle(self, s)
 |      Set the capstyle.
 |
 |      Parameters
 |      ----------
 |      s : {'butt', 'round', 'projecting'}
 |
 |  set_color(self, c)
 |      Set both the edgecolor and the facecolor.
 |
 |      Parameters
 |      ----------
 |      c : color
 |
 |      See Also
 |      --------
 |      Patch.set_facecolor, Patch.set_edgecolor
 |          For setting the edge or face color individually.
 |
 |  set_ec(self, color)
 |      Alias for `set_edgecolor`.
 |
 |  set_edgecolor(self, color)
 |      Set the patch edge color.
 |
 |      Parameters
 |      ----------
 |      color : color or None or 'auto'
 |
 |  set_facecolor(self, color)
 |      Set the patch face color.
 |
 |      Parameters
 |      ----------
 |      color : color or None
 |
 |  set_fc(self, color)
 |      Alias for `set_facecolor`.
 |
 |  set_fill(self, b)
 |      Set whether to fill the patch.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_hatch(self, hatch)
 |      Set the hatching pattern.
 |
 |      *hatch* can be one of::
 |
 |        /   - diagonal hatching
 |        \   - back diagonal
 |        |   - vertical
 |        -   - horizontal
 |        +   - crossed
 |        x   - crossed diagonal
 |        o   - small circle
 |        O   - large circle
 |        .   - dots
 |        *   - stars
 |
 |      Letters can be combined, in which case all the specified
 |      hatchings are done.  If same letter repeats, it increases the
 |      density of hatching of that pattern.
 |
 |      Hatching is supported in the PostScript, PDF, SVG and Agg
 |      backends only.
 |
 |      Parameters
 |      ----------
 |      hatch : {'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
 |
 |  set_joinstyle(self, s)
 |      Set the joinstyle.
 |
 |      Parameters
 |      ----------
 |      s : {'miter', 'round', 'bevel'}
 |
 |  set_linestyle(self, ls)
 |      Set the patch linestyle.
 |
 |      ===========================   =================
 |      linestyle                     description
 |      ===========================   =================
 |      ``'-'`` or ``'solid'``        solid line
 |      ``'--'`` or  ``'dashed'``     dashed line
 |      ``'-.'`` or  ``'dashdot'``    dash-dotted line
 |      ``':'`` or ``'dotted'``       dotted line
 |      ===========================   =================
 |
 |      Alternatively a dash tuple of the following form can be provided::
 |
 |          (offset, onoffseq)
 |
 |      where ``onoffseq`` is an even length tuple of on and off ink in points.
 |
 |      Parameters
 |      ----------
 |      ls : {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
 |          The line style.
 |
 |  set_linewidth(self, w)
 |      Set the patch linewidth in points.
 |
 |      Parameters
 |      ----------
 |      w : float or None
 |
 |  set_ls(self, ls)
 |      Alias for `set_linestyle`.
 |
 |  set_lw(self, w)
 |      Alias for `set_linewidth`.
 |
 |  update_from(self, other)
 |      Copy properties from *other* to *self*.
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from Patch:
 |
 |  fill
 |      Return whether the patch is filled.
 |
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from Patch:
 |
 |  validCap = ('butt', 'round', 'projecting')
 |
 |  validJoin = ('miter', 'round', 'bevel')
 |
 |  zorder = 1
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from matplotlib.artist.Artist:
 |
 |  __getstate__(self)
 |
 |  add_callback(self, func)
 |      Add a callback function that will be called whenever one of the
 |      `.Artist`'s properties changes.
 |
 |      Parameters
 |      ----------
 |      func : callable
 |          The callback function. It must have the signature::
 |
 |              def func(artist: Artist) -> Any
 |
 |          where *artist* is the calling `.Artist`. Return values may exist
 |          but are ignored.
 |
 |      Returns
 |      -------
 |      int
 |          The observer id associated with the callback. This id can be
 |          used for removing the callback with `.remove_callback` later.
 |
 |      See Also
 |      --------
 |      remove_callback
 |
 |  convert_xunits(self, x)
 |      Convert *x* using the unit type of the xaxis.
 |
 |      If the artist is not in contained in an Axes or if the xaxis does not
 |      have units, *x* itself is returned.
 |
 |  convert_yunits(self, y)
 |      Convert *y* using the unit type of the yaxis.
 |
 |      If the artist is not in contained in an Axes or if the yaxis does not
 |      have units, *y* itself is returned.
 |
 |  findobj(self, match=None, include_self=True)
 |      Find artist objects.
 |
 |      Recursively find all `.Artist` instances contained in the artist.
 |
 |      Parameters
 |      ----------
 |      match
 |          A filter criterion for the matches. This can be
 |
 |          - *None*: Return all objects contained in artist.
 |          - A function with signature ``def match(artist: Artist) -> bool``.
 |            The result will only contain artists for which the function
 |            returns *True*.
 |          - A class instance: e.g., `.Line2D`. The result will only contain
 |            artists of this class or its subclasses (``isinstance`` check).
 |
 |      include_self : bool
 |          Include *self* in the list to be checked for a match.
 |
 |      Returns
 |      -------
 |      list of `.Artist`
 |
 |  format_cursor_data(self, data)
 |      Return a string representation of *data*.
 |
 |      .. note::
 |          This method is intended to be overridden by artist subclasses.
 |          As an end-user of Matplotlib you will most likely not call this
 |          method yourself.
 |
 |      The default implementation converts ints and floats and arrays of ints
 |      and floats into a comma-separated string enclosed in square brackets.
 |
 |      See Also
 |      --------
 |      get_cursor_data
 |
 |  get_agg_filter(self)
 |      Return filter function to be used for agg filter.
 |
 |  get_alpha(self)
 |      Return the alpha value used for blending - not supported on all
 |      backends.
 |
 |  get_animated(self)
 |      Return whether the artist is animated.
 |
 |  get_children(self)
 |      Return a list of the child `.Artist`\s of this `.Artist`.
 |
 |  get_clip_box(self)
 |      Return the clipbox.
 |
 |  get_clip_on(self)
 |      Return whether the artist uses clipping.
 |
 |  get_clip_path(self)
 |      Return the clip path.
 |
 |  get_contains(self)
 |      [*Deprecated*] Return the custom contains function of the artist if set, or *None*.
 |
 |      See Also
 |      --------
 |      set_contains
 |
 |      Notes
 |      -----
 |      .. deprecated:: 3.3
 |
 |  get_cursor_data(self, event)
 |      Return the cursor data for a given event.
 |
 |      .. note::
 |          This method is intended to be overridden by artist subclasses.
 |          As an end-user of Matplotlib you will most likely not call this
 |          method yourself.
 |
 |      Cursor data can be used by Artists to provide additional context
 |      information for a given event. The default implementation just returns
 |      *None*.
 |
 |      Subclasses can override the method and return arbitrary data. However,
 |      when doing so, they must ensure that `.format_cursor_data` can convert
 |      the data to a string representation.
 |
 |      The only current use case is displaying the z-value of an `.AxesImage`
 |      in the status bar of a plot window, while moving the mouse.
 |
 |      Parameters
 |      ----------
 |      event : `matplotlib.backend_bases.MouseEvent`
 |
 |      See Also
 |      --------
 |      format_cursor_data
 |
 |  get_figure(self)
 |      Return the `.Figure` instance the artist belongs to.
 |
 |  get_gid(self)
 |      Return the group id.
 |
 |  get_in_layout(self)
 |      Return boolean flag, ``True`` if artist is included in layout
 |      calculations.
 |
 |      E.g. :doc:`/tutorials/intermediate/constrainedlayout_guide`,
 |      `.Figure.tight_layout()`, and
 |      ``fig.savefig(fname, bbox_inches='tight')``.
 |
 |  get_label(self)
 |      Return the label used for this artist in the legend.
 |
 |  get_path_effects(self)
 |
 |  get_picker(self)
 |      Return the picking behavior of the artist.
 |
 |      The possible values are described in `.set_picker`.
 |
 |      See Also
 |      --------
 |      set_picker, pickable, pick
 |
 |  get_rasterized(self)
 |      Return whether the artist is to be rasterized.
 |
 |  get_sketch_params(self)
 |      Return the sketch parameters for the artist.
 |
 |      Returns
 |      -------
 |      tuple or None
 |
 |          A 3-tuple with the following elements:
 |
 |          - *scale*: The amplitude of the wiggle perpendicular to the
 |            source line.
 |          - *length*: The length of the wiggle along the line.
 |          - *randomness*: The scale factor by which the length is
 |            shrunken or expanded.
 |
 |          Returns *None* if no sketch parameters were set.
 |
 |  get_snap(self)
 |      Return the snap setting.
 |
 |      See `.set_snap` for details.
 |
 |  get_tightbbox(self, renderer)
 |      Like `.Artist.get_window_extent`, but includes any clipping.
 |
 |      Parameters
 |      ----------
 |      renderer : `.RendererBase` subclass
 |          renderer that will be used to draw the figures (i.e.
 |          ``fig.canvas.get_renderer()``)
 |
 |      Returns
 |      -------
 |      `.Bbox`
 |          The enclosing bounding box (in figure pixel coordinates).
 |
 |  get_transformed_clip_path_and_affine(self)
 |      Return the clip path with the non-affine part of its
 |      transformation applied, and the remaining affine part of its
 |      transformation.
 |
 |  get_url(self)
 |      Return the url.
 |
 |  get_visible(self)
 |      Return the visibility.
 |
 |  get_zorder(self)
 |      Return the artist's zorder.
 |
 |  have_units(self)
 |      Return *True* if units are set on any axis.
 |
 |  is_transform_set(self)
 |      Return whether the Artist has an explicitly set transform.
 |
 |      This is *True* after `.set_transform` has been called.
 |
 |  pchanged(self)
 |      Call all of the registered callbacks.
 |
 |      This function is triggered internally when a property is changed.
 |
 |      See Also
 |      --------
 |      add_callback
 |      remove_callback
 |
 |  pick(self, mouseevent)
 |      Process a pick event.
 |
 |      Each child artist will fire a pick event if *mouseevent* is over
 |      the artist and the artist has picker set.
 |
 |      See Also
 |      --------
 |      set_picker, get_picker, pickable
 |
 |  pickable(self)
 |      Return whether the artist is pickable.
 |
 |      See Also
 |      --------
 |      set_picker, get_picker, pick
 |
 |  properties(self)
 |      Return a dictionary of all the properties of the artist.
 |
 |  remove(self)
 |      Remove the artist from the figure if possible.
 |
 |      The effect will not be visible until the figure is redrawn, e.g.,
 |      with `.FigureCanvasBase.draw_idle`.  Call `~.axes.Axes.relim` to
 |      update the axes limits if desired.
 |
 |      Note: `~.axes.Axes.relim` will not see collections even if the
 |      collection was added to the axes with *autolim* = True.
 |
 |      Note: there is no support for removing the artist's legend entry.
 |
 |  remove_callback(self, oid)
 |      Remove a callback based on its observer id.
 |
 |      See Also
 |      --------
 |      add_callback
 |
 |  set(self, **kwargs)
 |      A property batch setter.  Pass *kwargs* to set properties.
 |
 |  set_agg_filter(self, filter_func)
 |      Set the agg filter.
 |
 |      Parameters
 |      ----------
 |      filter_func : callable
 |          A filter function, which takes a (m, n, 3) float array and a dpi
 |          value, and returns a (m, n, 3) array.
 |
 |          .. ACCEPTS: a filter function, which takes a (m, n, 3) float array
 |              and a dpi value, and returns a (m, n, 3) array
 |
 |  set_animated(self, b)
 |      Set the artist's animation state.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_clip_box(self, clipbox)
 |      Set the artist's clip `.Bbox`.
 |
 |      Parameters
 |      ----------
 |      clipbox : `.Bbox`
 |
 |  set_clip_on(self, b)
 |      Set whether the artist uses clipping.
 |
 |      When False artists will be visible outside of the axes which
 |      can lead to unexpected results.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_clip_path(self, path, transform=None)
 |      Set the artist's clip path.
 |
 |      Parameters
 |      ----------
 |      path : `.Patch` or `.Path` or `.TransformedPath` or None
 |          The clip path. If given a `.Path`, *transform* must be provided as
 |          well. If *None*, a previously set clip path is removed.
 |      transform : `~matplotlib.transforms.Transform`, optional
 |          Only used if *path* is a `.Path`, in which case the given `.Path`
 |          is converted to a `.TransformedPath` using *transform*.
 |
 |      Notes
 |      -----
 |      For efficiency, if *path* is a `.Rectangle` this method will set the
 |      clipping box to the corresponding rectangle and set the clipping path
 |      to ``None``.
 |
 |      For technical reasons (support of `~.Artist.set`), a tuple
 |      (*path*, *transform*) is also accepted as a single positional
 |      parameter.
 |
 |      .. ACCEPTS: Patch or (Path, Transform) or None
 |
 |  set_contains(self, picker)
 |      [*Deprecated*] Define a custom contains syntax for the artist.
 |
 |      The provided callable replaces the default `.contains` method
 |      of the artist.
 |
 |      Parameters
 |      ----------
 |      picker : callable
 |          A custom picker function to evaluate if an event is within the
 |          artist. The function must have the signature::
 |
 |              def contains(artist: Artist, event: MouseEvent) -> bool, dict
 |
 |          that returns:
 |
 |          - a bool indicating if the event is within the artist
 |          - a dict of additional information. The dict should at least
 |            return the same information as the default ``contains()``
 |            implementation of the respective artist, but may provide
 |            additional information.
 |
 |      Notes
 |      -----
 |      .. deprecated:: 3.3
 |
 |  set_figure(self, fig)
 |      Set the `.Figure` instance the artist belongs to.
 |
 |      Parameters
 |      ----------
 |      fig : `.Figure`
 |
 |  set_gid(self, gid)
 |      Set the (group) id for the artist.
 |
 |      Parameters
 |      ----------
 |      gid : str
 |
 |  set_in_layout(self, in_layout)
 |      Set if artist is to be included in layout calculations,
 |      E.g. :doc:`/tutorials/intermediate/constrainedlayout_guide`,
 |      `.Figure.tight_layout()`, and
 |      ``fig.savefig(fname, bbox_inches='tight')``.
 |
 |      Parameters
 |      ----------
 |      in_layout : bool
 |
 |  set_label(self, s)
 |      Set a label that will be displayed in the legend.
 |
 |      Parameters
 |      ----------
 |      s : object
 |          *s* will be converted to a string by calling `str`.
 |
 |  set_path_effects(self, path_effects)
 |      Set the path effects.
 |
 |      Parameters
 |      ----------
 |      path_effects : `.AbstractPathEffect`
 |
 |  set_picker(self, picker)
 |      Define the picking behavior of the artist.
 |
 |      Parameters
 |      ----------
 |      picker : None or bool or callable
 |          This can be one of the following:
 |
 |          - *None*: Picking is disabled for this artist (default).
 |
 |          - A boolean: If *True* then picking will be enabled and the
 |            artist will fire a pick event if the mouse event is over
 |            the artist.
 |
 |          - A function: If picker is callable, it is a user supplied
 |            function which determines whether the artist is hit by the
 |            mouse event::
 |
 |              hit, props = picker(artist, mouseevent)
 |
 |            to determine the hit syntax.  if the mouse event is over the
 |            artist, return *hit=True* and props is a dictionary of
 |            properties you want added to the PickEvent attributes.
 |
 |          - *deprecated*: For `.Line2D` only, *picker* can also be a float
 |            that sets the tolerance for checking whether an event occurred
 |            "on" the line; this is deprecated.  Use `.Line2D.set_pickradius`
 |            instead.
 |
 |  set_rasterized(self, rasterized)
 |      Force rasterized (bitmap) drawing in vector backend output.
 |
 |      Defaults to None, which implies the backend's default behavior.
 |
 |      Parameters
 |      ----------
 |      rasterized : bool or None
 |
 |  set_sketch_params(self, scale=None, length=None, randomness=None)
 |      Sets the sketch parameters.
 |
 |      Parameters
 |      ----------
 |      scale : float, optional
 |          The amplitude of the wiggle perpendicular to the source
 |          line, in pixels.  If scale is `None`, or not provided, no
 |          sketch filter will be provided.
 |      length : float, optional
 |           The length of the wiggle along the line, in pixels
 |           (default 128.0)
 |      randomness : float, optional
 |          The scale factor by which the length is shrunken or
 |          expanded (default 16.0)
 |
 |          .. ACCEPTS: (scale: float, length: float, randomness: float)
 |
 |  set_snap(self, snap)
 |      Set the snapping behavior.
 |
 |      Snapping aligns positions with the pixel grid, which results in
 |      clearer images. For example, if a black line of 1px width was
 |      defined at a position in between two pixels, the resulting image
 |      would contain the interpolated value of that line in the pixel grid,
 |      which would be a grey value on both adjacent pixel positions. In
 |      contrast, snapping will move the line to the nearest integer pixel
 |      value, so that the resulting image will really contain a 1px wide
 |      black line.
 |
 |      Snapping is currently only supported by the Agg and MacOSX backends.
 |
 |      Parameters
 |      ----------
 |      snap : bool or None
 |          Possible values:
 |
 |          - *True*: Snap vertices to the nearest pixel center.
 |          - *False*: Do not modify vertex positions.
 |          - *None*: (auto) If the path contains only rectilinear line
 |            segments, round to the nearest pixel center.
 |
 |  set_transform(self, t)
 |      Set the artist transform.
 |
 |      Parameters
 |      ----------
 |      t : `.Transform`
 |
 |  set_url(self, url)
 |      Set the url for the artist.
 |
 |      Parameters
 |      ----------
 |      url : str
 |
 |  set_visible(self, b)
 |      Set the artist's visibility.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_zorder(self, level)
 |      Set the zorder for the artist.  Artists with lower zorder
 |      values are drawn first.
 |
 |      Parameters
 |      ----------
 |      level : float
 |
 |  update(self, props)
 |      Update this artist's properties from the dict *props*.
 |
 |      Parameters
 |      ----------
 |      props : dict
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from matplotlib.artist.Artist:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)
 |
 |  axes
 |      The `~.axes.Axes` instance the artist resides in, or *None*.
 |
 |  mouseover
 |      If this property is set to *True*, the artist will be queried for
 |      custom context information when the mouse cursor moves over it.
 |
 |      See also :meth:`get_cursor_data`, :class:`.ToolCursorPosition` and
 |      :class:`.NavigationToolbar2`.
 |
 |  stale
 |      Whether the artist is 'stale' and needs to be re-drawn for the output
 |      to match the internal state of the artist.
 |
 |  sticky_edges
 |      ``x`` and ``y`` sticky edge lists for autoscaling.
 |
 |      When performing autoscaling, if a data limit coincides with a value in
 |      the corresponding sticky_edges list, then no margin will be added--the
 |      view limit "sticks" to the edge. A typical use case is histograms,
 |      where one usually expects no margin on the bottom edge (0) of the
 |      histogram.
 |
 |      This attribute cannot be assigned to; however, the ``x`` and ``y``
 |      lists can be modified in place as needed.
 |
 |      Examples
 |      --------
 |      >>> artist.sticky_edges.x[:] = (xmin, xmax)
 |      >>> artist.sticky_edges.y[:] = (ymin, ymax)

        """
        fig, ax = plt.subplots()
        cx, cy, r, t1, t2, w = 0.1, 0.15, 0.6, 30, 80, 0.2
        wedge = DemoPatch.patches.Wedge((cx, cy), r, t1, t2, w)
        ax.add_patch(wedge)
        wedge2 = DemoPatch.patches.Wedge((cx, cy), 0.1, 0, t1, alpha=0.45, color='y')
        ax.add_patch(wedge2)
        wedge3 = DemoPatch.patches.Wedge((cx, cy), 0.05, 0, t2, alpha=0.55, color='g')
        ax.add_patch(wedge3)
        r2 = r - w
        x1 = [cx, cx + r2*np.cos(t1/360*np.pi*2)]
        y1 = [cy, cy + r2*np.sin(t1/360*np.pi*2)]
        x2 = [cx, cx + r2*np.cos(t2/360*np.pi*2)]
        y2 = [cy, cy + r2*np.sin(t2/360*np.pi*2)]
        x3 = [cx, cx + r]
        y3 = [cy, cy]
        ax.plot(x1, y1, 'r--', x2, y2, 'r--', x3, y3, 'r--')
        ax.set(aspect=1,
               xlim=(0, 0.8), ylim=(0, 0.8),
               title=f'center=({cx}, {cy}), r={r}, theta1={t1}, \ntheta2={t2}, width={w}'
               )
        ax.text(cx-0.08, cy-0.01, f'center\n({cx}, {cy})', va='top', bbox=dict(pad=0, alpha=0.1))
        ax.annotate(text=f'theta1={t1}'+r'$^{\circ}$',
                    xytext=(cx+0.25, cy+0.1),
                    xy=(cx+0.1, cy+0.02),
                    arrowprops=dict(width=0.5, alpha=0.3),
                    bbox=dict(color='purple', alpha=0.3)
                    )
        ax.annotate(text=f'theta2={t2}'+r'$^{\circ}$',
                    xytext=(0.02, 0.4),
                    xy=(cx+0.02, cy+0.05),
                    arrowprops=dict(width=0.5, alpha=0.3),
                    bbox=dict(color='purple', alpha=0.3)
                    )

    @staticmethod
    def add_patch_use_mgrid():
        # import matplotlib.path as mpath
        import matplotlib.lines as mlines
        import matplotlib.patches as mpatches
        from matplotlib.collections import PatchCollection

        # 定义函数，给每一个patch都设置标签说明
        def label(xy, text):
            # 标签放置在patch下方的0.15位置处
            plt.text(xy[0], xy[1] - 0.15, text, ha="center", family='sans-serif', size=14)

        fig, ax = plt.subplots()

        # 创建一个3x3的网格
        grid = np.mgrid[0.2:0.8:3j, 0.2:0.8:3j].reshape(2, -1).T

        #创建容纳patch的集合
        patches = []

        # 添加一个圆Circle
        circle = mpatches.Circle(grid[0], 0.1, ec="none")
        patches.append(circle)
        label(grid[0], "Circle")

        # 添加一个Rectangle
        rect = mpatches.Rectangle(grid[1] - [0.025, 0.05], 0.05, 0.1, ec="none")
        patches.append(rect)
        label(grid[1], "Rectangle")

        # 添加一个楔形，即圆的一部分
        wedge = mpatches.Wedge(grid[2], 0.1, 30, 270, ec="none")
        patches.append(wedge)
        label(grid[2], "Wedge")

        # 添加一多边形，这里添加一个五边形
        polygon = mpatches.RegularPolygon(grid[3], 5, 0.1)
        patches.append(polygon)
        label(grid[3], "Polygon")

        # 添加一个椭圆，也可以使用Arc
        ellipse = mpatches.Ellipse(grid[4], 0.2, 0.1)
        patches.append(ellipse)
        label(grid[4], "Ellipse")

        # 添加一个箭头
        arrow = mpatches.Arrow(grid[5, 0] - 0.05, grid[5, 1] - 0.05, 0.1, 0.1, width=0.1)
        patches.append(arrow)
        label(grid[5], "Arrow")

        # 添加一个路径path
        # Path = mpath.Path
        # path_data = [(Path.MOVETO, [0.018, -0.11]),
        #              (Path.CURVE4, [-0.031, -0.051]),
        #              (Path.CURVE4, [-0.115, 0.073]),
        #              (Path.CURVE4, [-0.03, 0.073]),
        #              (Path.LINETO, [-0.011, 0.039]),
        #              (Path.CURVE4, [0.043, 0.121]),
        #              (Path.CURVE4, [0.075, -0.005]),
        #              (Path.CURVE4, [0.035, -0.027]),
        #              (Path.CLOSEPOLY, [0.018, -0.11])]
        # codes, verts = zip(*path_data)
        # path = mpath.Path(verts + grid[6], codes)
        # patch = mpatches.PathPatch(path)
        # patches.append(patch)
        # label(grid[6], "PathPatch")

        # 添加一个box
        fancybox = mpatches.FancyBboxPatch(
            grid[6] - [0.025, 0.05], 0.05, 0.1, boxstyle=mpatches.BoxStyle("Round", pad=0.02))
        patches.append(fancybox)
        label(grid[6], "FancyBboxPatch")

        # 添加一条折线——注意这里的折线和前面所画的这显示不一样的，这里的折线是一个形状
        x, y = np.array([[-0.06, 0.0, 0.1], [0.05, -0.05, 0.05]])
        line = mlines.Line2D(x + grid[7, 0], y + grid[7, 1], lw=5., alpha=0.3)
        label(grid[7], "Line2D")

        # 添加一个扇形Wedge
        # x, y = np.array([[-0.06, 0.0, 0.1], [0.05, -0.05, 0.05]])
        # line = mlines.Line2D(x + grid[8, 0], y + grid[8, 1], lw=5., alpha=0.3)
        wedge = mpatches.Wedge(grid[8], 0.1, 10, 50)
        patches.append(wedge)
        label(grid[8], "Wedge")

        # 将patch集合包装成PatchCollection
        # colors = np.linspace(0, 1, len(patches))
        collection = PatchCollection(patches, cmap=plt.cm.hsv, alpha=0.3)
        # collection.set_array(np.array(colors))

        # 将PatchCollection添加给axes对象
        ax.add_collection(collection)

        # 将折线添加到axes对象
        ax.add_line(line)

        plt.axis('equal')
        plt.axis('off')
        plt.tight_layout()
        plt.show()

    @staticmethod
    def add_patch_gridspec():
        patches = DemoPatch.patches

        # create figure
        fig = plt.figure()

        # create grid in figure
        grid = plt.GridSpec(3, 3, fig)
        axs = []
        for i in range(3):
            for j in range(3):
                ax = fig.add_subplot(grid[i, j])
                # mode-1: set off axis and spines
                for pos in ax.spines:
                    ax.spines[pos].set_color('none')
                    ax.xaxis.set_visible(False)
                    ax.yaxis.set_visible(False)
                # mode-2: set off axis and spines
                # ax.set_frame_on(False)
                # ax.set_xticks([])
                # ax.set_yticks([])
                axs.append(ax)

        patches_list = []
        labels = []
        # 添加Circle
        circle = patches.Circle((0.5, 0.5), 0.35, ec="none")
        patches_list.append(circle)
        labels.append("Circle")

        # 添加Arc
        circle = patches.Arc((0.5, 0.5), 0.35, 10, 60)
        patches_list.append(circle)
        labels.append("Arc")


        for j, p in enumerate(patches_list):
            axs[j].add_patch(p)
            axs[j].text(0.5, 0 - 0.15, labels[j], ha="center", family='sans-serif', size=14)


class DemoPath:

    """
class Path(builtins.object)
 |  Path(vertices, codes=None, _interpolation_steps=1, closed=False, readonly=False)
 |
 |  A series of possibly disconnected, possibly closed, line and curve
 |  segments.
 |
 |  The underlying storage is made up of two parallel numpy arrays:
 |
 |  - *vertices*: an Nx2 float array of vertices
 |  - *codes*: an N-length uint8 array of vertex types, or None
 |
 |  These two arrays always have the same length in the first
 |  dimension.  For example, to represent a cubic curve, you must
 |  provide three vertices as well as three codes ``CURVE3``.
 |
 |  The code types are:
 |
 |  - ``STOP``   :  1 vertex (ignored)
 |      A marker for the end of the entire path (currently not required and
 |      ignored)
 |
 |  - ``MOVETO`` :  1 vertex
 |      Pick up the pen and move to the given vertex.
 |
 |  - ``LINETO`` :  1 vertex
 |      Draw a line from the current position to the given vertex.
 |
 |  - ``CURVE3`` :  1 control point, 1 endpoint
 |      Draw a quadratic Bezier curve from the current position, with the given
 |      control point, to the given end point.
 |
 |  - ``CURVE4`` :  2 control points, 1 endpoint
 |      Draw a cubic Bezier curve from the current position, with the given
 |      control points, to the given end point.
 |
 |  - ``CLOSEPOLY`` : 1 vertex (ignored)
 |      Draw a line segment to the start point of the current polyline.
 |
 |  If *codes* is None, it is interpreted as a ``MOVETO`` followed by a series
 |  of ``LINETO``.
 |
 |  Users of Path objects should not access the vertices and codes arrays
 |  directly.  Instead, they should use `iter_segments` or `cleaned` to get the
 |  vertex/code pairs.  This helps, in particular, to consistently handle the
 |  case of *codes* being None.
 |
 |  Some behavior of Path objects can be controlled by rcParams. See the
 |  rcParams whose keys start with 'path.'.
 |
 |  .. note::
 |
 |      The vertices and codes arrays should be treated as
 |      immutable -- there are a number of optimizations and assumptions
 |      made up front in the constructor that will not change when the
 |      data changes.
 |
 |  Methods defined here:
 |
 |  __copy__(self)
 |      Return a shallow copy of the `Path`, which will share the
 |      vertices and codes with the source `Path`.
 |
 |  __deepcopy__(self, memo=None)
 |      Return a deepcopy of the `Path`.  The `Path` will not be
 |      readonly, even if the source `Path` is.
 |
 |  __init__(self, vertices, codes=None, _interpolation_steps=1, closed=False, readonly=False)
 |      Create a new path with the given vertices and codes.
 |
 |      Parameters
 |      ----------
 |      vertices : (N, 2) array-like
 |          The path vertices, as an array, masked array or sequence of pairs.
 |          Masked values, if any, will be converted to NaNs, which are then
 |          handled correctly by the Agg PathIterator and other consumers of
 |          path data, such as :meth:`iter_segments`.
 |      codes : array-like or None, optional
 |          n-length array integers representing the codes of the path.
 |          If not None, codes must be the same length as vertices.
 |          If None, *vertices* will be treated as a series of line segments.
 |      _interpolation_steps : int, optional
 |          Used as a hint to certain projections, such as Polar, that this
 |          path should be linearly interpolated immediately before drawing.
 |          This attribute is primarily an implementation detail and is not
 |          intended for public use.
 |      closed : bool, optional
 |          If *codes* is None and closed is True, vertices will be treated as
 |          line segments of a closed polygon.  Note that the last vertex will
 |          then be ignored (as the corresponding code will be set to
 |          CLOSEPOLY).
 |      readonly : bool, optional
 |          Makes the path behave in an immutable way and sets the vertices
 |          and codes as read-only arrays.
 |
 |  __len__(self)
 |
 |  __repr__(self)
 |      Return repr(self).
 |
 |  cleaned(self, transform=None, remove_nans=False, clip=None, quantize=<deprecated parameter>, simplify=False, curves=False, stroke_width=1.0, snap=False, sketch=None)
 |      Return a new Path with vertices and codes cleaned according to the
 |      parameters.
 |
 |      See Also
 |      --------
 |      Path.iter_segments : for details of the keyword arguments.
 |
 |  clip_to_bbox(self, bbox, inside=True)
 |      Clip the path to the given bounding box.
 |
 |      The path must be made up of one or more closed polygons.  This
 |      algorithm will not behave correctly for unclosed paths.
 |
 |      If *inside* is `True`, clip to the inside of the box, otherwise
 |      to the outside of the box.
 |
 |  contains_path(self, path, transform=None)
 |      Return whether this (closed) path completely contains the given path.
 |
 |      If *transform* is not ``None``, the path will be transformed before
 |      checking for containment.
 |
 |  contains_point(self, point, transform=None, radius=0.0)
 |      Return whether the area enclosed by the path contains the given point.
 |
 |      The path is always treated as closed; i.e. if the last code is not
 |      CLOSEPOLY an implicit segment connecting the last vertex to the first
 |      vertex is assumed.
 |
 |      Parameters
 |      ----------
 |      point : (float, float)
 |          The point (x, y) to check.
 |      transform : `matplotlib.transforms.Transform`, optional
 |          If not ``None``, *point* will be compared to ``self`` transformed
 |          by *transform*; i.e. for a correct check, *transform* should
 |          transform the path into the coordinate system of *point*.
 |      radius : float, default: 0
 |          Add an additional margin on the path in coordinates of *point*.
 |          The path is extended tangentially by *radius/2*; i.e. if you would
 |          draw the path with a linewidth of *radius*, all points on the line
 |          would still be considered to be contained in the area. Conversely,
 |          negative values shrink the area: Points on the imaginary line
 |          will be considered outside the area.
 |
 |      Returns
 |      -------
 |      bool
 |
 |      Notes
 |      -----
 |      The current algorithm has some limitations:
 |
 |      - The result is undefined for points exactly at the boundary
 |        (i.e. at the path shifted by *radius/2*).
 |      - The result is undefined if there is no enclosed area, i.e. all
 |        vertices are on a straight line.
 |      - If bounding lines start to cross each other due to *radius* shift,
 |        the result is not guaranteed to be correct.
 |
 |  contains_points(self, points, transform=None, radius=0.0)
 |      Return whether the area enclosed by the path contains the given points.
 |
 |      The path is always treated as closed; i.e. if the last code is not
 |      CLOSEPOLY an implicit segment connecting the last vertex to the first
 |      vertex is assumed.
 |
 |      Parameters
 |      ----------
 |      points : (N, 2) array
 |          The points to check. Columns contain x and y values.
 |      transform : `matplotlib.transforms.Transform`, optional
 |          If not ``None``, *points* will be compared to ``self`` transformed
 |          by *transform*; i.e. for a correct check, *transform* should
 |          transform the path into the coordinate system of *points*.
 |      radius : float, default: 0
 |          Add an additional margin on the path in coordinates of *points*.
 |          The path is extended tangentially by *radius/2*; i.e. if you would
 |          draw the path with a linewidth of *radius*, all points on the line
 |          would still be considered to be contained in the area. Conversely,
 |          negative values shrink the area: Points on the imaginary line
 |          will be considered outside the area.
 |
 |      Returns
 |      -------
 |      length-N bool array
 |
 |      Notes
 |      -----
 |      The current algorithm has some limitations:
 |
 |      - The result is undefined for points exactly at the boundary
 |        (i.e. at the path shifted by *radius/2*).
 |      - The result is undefined if there is no enclosed area, i.e. all
 |        vertices are on a straight line.
 |      - If bounding lines start to cross each other due to *radius* shift,
 |        the result is not guaranteed to be correct.
 |
 |  copy = __copy__(self)
 |
 |  deepcopy = __deepcopy__(self, memo=None)
 |
 |  get_extents(self, transform=None, **kwargs)
 |      Get Bbox of the path.
 |
 |      Parameters
 |      ----------
 |      transform : matplotlib.transforms.Transform, optional
 |          Transform to apply to path before computing extents, if any.
 |      **kwargs
 |          Forwarded to `.iter_bezier`.
 |
 |      Returns
 |      -------
 |      matplotlib.transforms.Bbox
 |          The extents of the path Bbox([[xmin, ymin], [xmax, ymax]])
 |
 |  interpolated(self, steps)
 |      Return a new path resampled to length N x steps.
 |
 |      Codes other than LINETO are not handled correctly.
 |
 |  intersects_bbox(self, bbox, filled=True)
 |      Return whether this path intersects a given `~.transforms.Bbox`.
 |
 |      If *filled* is True, then this also returns True if the path completely
 |      encloses the `.Bbox` (i.e., the path is treated as filled).
 |
 |      The bounding box is always considered filled.
 |
 |  intersects_path(self, other, filled=True)
 |      Return whether if this path intersects another given path.
 |
 |      If *filled* is True, then this also returns True if one path completely
 |      encloses the other (i.e., the paths are treated as filled).
 |
 |  iter_bezier(self, **kwargs)
 |      Iterate over each bezier curve (lines included) in a Path.
 |
 |      Parameters
 |      ----------
 |      **kwargs
 |          Forwarded to `.iter_segments`.
 |
 |      Yields
 |      ------
 |      B : matplotlib.bezier.BezierSegment
 |          The bezier curves that make up the current path. Note in particular
 |          that freestanding points are bezier curves of order 0, and lines
 |          are bezier curves of order 1 (with two control points).
 |      code : Path.code_type
 |          The code describing what kind of curve is being returned.
 |          Path.MOVETO, Path.LINETO, Path.CURVE3, Path.CURVE4 correspond to
 |          bezier curves with 1, 2, 3, and 4 control points (respectively).
 |          Path.CLOSEPOLY is a Path.LINETO with the control points correctly
 |          chosen based on the start/end points of the current stroke.
 |
 |  iter_segments(self, transform=None, remove_nans=True, clip=None, snap=False, stroke_width=1.0, simplify=None, curves=True, sketch=None)
 |      Iterate over all curve segments in the path.
 |
 |      Each iteration returns a pair ``(vertices, code)``, where ``vertices``
 |      is a sequence of 1-3 coordinate pairs, and ``code`` is a `Path` code.
 |
 |      Additionally, this method can provide a number of standard cleanups and
 |      conversions to the path.
 |
 |      Parameters
 |      ----------
 |      transform : None or :class:`~matplotlib.transforms.Transform`
 |          If not None, the given affine transformation will be applied to the
 |          path.
 |      remove_nans : bool, optional
 |          Whether to remove all NaNs from the path and skip over them using
 |          MOVETO commands.
 |      clip : None or (float, float, float, float), optional
 |          If not None, must be a four-tuple (x1, y1, x2, y2)
 |          defining a rectangle in which to clip the path.
 |      snap : None or bool, optional
 |          If True, snap all nodes to pixels; if False, don't snap them.
 |          If None, snap if the path contains only segments
 |          parallel to the x or y axes, and no more than 1024 of them.
 |      stroke_width : float, optional
 |          The width of the stroke being drawn (used for path snapping).
 |      simplify : None or bool, optional
 |          Whether to simplify the path by removing vertices
 |          that do not affect its appearance.  If None, use the
 |          :attr:`should_simplify` attribute.  See also :rc:`path.simplify`
 |          and :rc:`path.simplify_threshold`.
 |      curves : bool, optional
 |          If True, curve segments will be returned as curve segments.
 |          If False, all curves will be converted to line segments.
 |      sketch : None or sequence, optional
 |          If not None, must be a 3-tuple of the form
 |          (scale, length, randomness), representing the sketch parameters.
 |
 |  to_polygons(self, transform=None, width=0, height=0, closed_only=True)
 |      Convert this path to a list of polygons or polylines.  Each
 |      polygon/polyline is an Nx2 array of vertices.  In other words,
 |      each polygon has no ``MOVETO`` instructions or curves.  This
 |      is useful for displaying in backends that do not support
 |      compound paths or Bezier curves.
 |
 |      If *width* and *height* are both non-zero then the lines will
 |      be simplified so that vertices outside of (0, 0), (width,
 |      height) will be clipped.
 |
 |      If *closed_only* is `True` (default), only closed polygons,
 |      with the last point being the same as the first point, will be
 |      returned.  Any unclosed polylines in the path will be
 |      explicitly closed.  If *closed_only* is `False`, any unclosed
 |      polygons in the path will be returned as unclosed polygons,
 |      and the closed polygons will be returned explicitly closed by
 |      setting the last point to the same as the first point.
 |
 |  transformed(self, transform)
 |      Return a transformed copy of the path.
 |
 |      See Also
 |      --------
 |      matplotlib.transforms.TransformedPath
 |          A specialized path class that will cache the transformed result and
 |          automatically update when the transform changes.
 |
 |  ----------------------------------------------------------------------
 |  Class methods defined here:
 |
 |  arc(theta1, theta2, n=None, is_wedge=False) from builtins.type
 |      Return the unit circle arc from angles *theta1* to *theta2* (in
 |      degrees).
 |
 |      *theta2* is unwrapped to produce the shortest arc within 360 degrees.
 |      That is, if *theta2* > *theta1* + 360, the arc will be from *theta1* to
 |      *theta2* - 360 and not a full circle plus some extra overlap.
 |
 |      If *n* is provided, it is the number of spline segments to make.
 |      If *n* is not provided, the number of spline segments is
 |      determined based on the delta between *theta1* and *theta2*.
 |
 |         Masionobe, L.  2003.  `Drawing an elliptical arc using
 |         polylines, quadratic or cubic Bezier curves
 |         <http://www.spaceroots.org/documents/ellipse/index.html>`_.
 |
 |  circle(center=(0.0, 0.0), radius=1.0, readonly=False) from builtins.type
 |      Return a `Path` representing a circle of a given radius and center.
 |
 |      Parameters
 |      ----------
 |      center : (float, float), default: (0, 0)
 |          The center of the circle.
 |      radius : float, default: 1
 |          The radius of the circle.
 |      readonly : bool
 |          Whether the created path should have the "readonly" argument
 |          set when creating the Path instance.
 |
 |      Notes
 |      -----
 |      The circle is approximated using 8 cubic Bezier curves, as described in
 |
 |        Lancaster, Don.  `Approximating a Circle or an Ellipse Using Four
 |        Bezier Cubic Splines <https://www.tinaja.com/glib/ellipse4.pdf>`_.
 |
 |  make_compound_path(*args) from builtins.type
 |      Make a compound path from a list of Path objects. Blindly removes all
 |      Path.STOP control points.
 |
 |  make_compound_path_from_polys(XY) from builtins.type
 |      Make a compound path object to draw a number
 |      of polygons with equal numbers of sides XY is a (numpolys x
 |      numsides x 2) numpy array of vertices.  Return object is a
 |      :class:`Path`
 |
 |      .. plot:: gallery/misc/histogram_path.py
 |
 |  unit_circle() from builtins.type
 |      Return the readonly :class:`Path` of the unit circle.
 |
 |      For most cases, :func:`Path.circle` will be what you want.
 |
 |  unit_circle_righthalf() from builtins.type
 |      Return a `Path` of the right half of a unit circle.
 |
 |      See `Path.circle` for the reference on the approximation used.
 |
 |  unit_rectangle() from builtins.type
 |      Return a `Path` instance of the unit rectangle from (0, 0) to (1, 1).
 |
 |  unit_regular_asterisk(numVertices) from builtins.type
 |      Return a :class:`Path` for a unit regular asterisk with the given
 |      numVertices and radius of 1.0, centered at (0, 0).
 |
 |  unit_regular_polygon(numVertices) from builtins.type
 |      Return a :class:`Path` instance for a unit regular polygon with the
 |      given *numVertices* such that the circumscribing circle has radius 1.0,
 |      centered at (0, 0).
 |
 |  unit_regular_star(numVertices, innerCircle=0.5) from builtins.type
 |      Return a :class:`Path` for a unit regular star with the given
 |      numVertices and radius of 1.0, centered at (0, 0).
 |
 |  wedge(theta1, theta2, n=None) from builtins.type
 |      Return the unit circle wedge from angles *theta1* to *theta2* (in
 |      degrees).
 |
 |      *theta2* is unwrapped to produce the shortest wedge within 360 degrees.
 |      That is, if *theta2* > *theta1* + 360, the wedge will be from *theta1*
 |      to *theta2* - 360 and not a full circle plus some extra overlap.
 |
 |      If *n* is provided, it is the number of spline segments to make.
 |      If *n* is not provided, the number of spline segments is
 |      determined based on the delta between *theta1* and *theta2*.
 |
 |      See `Path.arc` for the reference on the approximation used.
 |
 |  ----------------------------------------------------------------------
 |  Static methods defined here:
 |
 |  hatch(hatchpattern, density=6)
 |      Given a hatch specifier, *hatchpattern*, generates a Path that
 |      can be used in a repeated hatching pattern.  *density* is the
 |      number of lines per unit square.
 |
 |  ----------------------------------------------------------------------
 |  Readonly properties defined here:
 |
 |  readonly
 |      `True` if the `Path` is read-only.
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)
 |
 |  codes
 |      The list of codes in the `Path` as a 1D numpy array.  Each
 |      code is one of `STOP`, `MOVETO`, `LINETO`, `CURVE3`, `CURVE4`
 |      or `CLOSEPOLY`.  For codes that correspond to more than one
 |      vertex (`CURVE3` and `CURVE4`), that code will be repeated so
 |      that the length of `self.vertices` and `self.codes` is always
 |      the same.
 |
 |  should_simplify
 |      `True` if the vertices array should be simplified.
 |
 |  simplify_threshold
 |      The fraction of a pixel difference below which vertices will
 |      be simplified out.
 |
 |  vertices
 |      The list of vertices in the `Path` as an Nx2 numpy array.
 |
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |
 |  CLOSEPOLY = 79
 |
 |  CURVE3 = 3
 |
 |  CURVE4 = 4
 |
 |  LINETO = 2
 |
 |  MOVETO = 1
 |
 |  NUM_VERTICES_FOR_CODE = {0: 1, 1: 1, 2: 1, 3: 2, 4: 3, 79: 1}
 |
 |  STOP = 0
 |
 |  code_type = <class 'numpy.uint8'>
 |      Unsigned integer type, compatible with C ``unsigned char``.
 |
 |      :Character code: ``'B'``
 |      :Canonical name: `numpy.ubyte`
 |      :Alias on this platform (Windows AMD64): `numpy.uint8`: 8-bit unsigned integer (``0`` to ``255``).
    """

    from matplotlib.path import Path
    from matplotlib import patches

    @staticmethod
    def path_exp_from_matplotlib():
        Path = DemoPath.Path
        mpatches = DemoPath.patches

        path_data = [
            (Path.MOVETO, [0.018, -0.11]),      # 移动画笔起点（过程中不绘图）
            (Path.CURVE4, [-0.031, -0.051]),    # 曲线连接，两个端点，一个控制点
            (Path.CURVE4, [-0.115, 0.073]),
            (Path.CURVE4, [-0.03, 0.073]),
            (Path.LINETO, [-0.011, 0.039]),     # 从当前点绘制直线到目标点
            (Path.CURVE4, [0.043, 0.121]),      # 曲线连接，两个端点，一个控制点
            (Path.CURVE4, [0.075, -0.005]),
            (Path.CURVE4, [0.035, -0.027]),
            (Path.CLOSEPOLY, [0.018, -0.11])    # 闭合到起点
            ]

        # codes, verts = zip(*path_data)          # 使用zip函数生成编码、顶点序列
        # path = Path(verts, codes)               # 使用顶点、编码创建Path

        mypath = Path(
            vertices=[x[1] for x in path_data],
            codes=[x[0] for x in path_data]
        )
        pathpatch = mpatches.PathPatch(mypath)    # 将path包装成PathPatch

        pathpatch.set_color('g')
        pathpatch.set_hatch('*')
        pathpatch.set_alpha(0.3)

        fig, ax = plt.subplots()
        ax.add_patch(pathpatch)                 # 将路径对象加入子图

        # plot control points and connecting lines
        x, y = zip(*mypath.vertices)
        ax.plot(x, y, 'ro-')

        # ax.grid()
        ax.axis('equal')
        plt.show()

    @staticmethod
    def path_drum_by_hexagon():
        from matplotlib.path import Path

        fig, ax = plt.subplots()

        verts = [(1, 1),
                 (2, 1),
                 (2.5, 1+np.sqrt(3)/2),
                 (2, 1+np.sqrt(3)),
                 (1, 1+np.sqrt(3)),
                 (0.5, 1+np.sqrt(3)/2),
                 (1, 1)
                 ]
        codes = [Path.MOVETO,
                 Path.LINETO,
                 Path.CURVE3,
                 Path.LINETO,
                 Path.LINETO,
                 Path.CURVE3,
                 Path.LINETO,
                 # Path.CLOSEPOLY
                 ]
        # create Path, PathPatch
        mypath = Path(vertices=verts, codes=codes)
        pathpatch = mpl.patches.PathPatch(mypath)     # 将path包装成PathPatch
        # add to Axes
        ax.add_patch(pathpatch)                 # 将路径对象加入子图
        # set attributes
        pathpatch.set_color('g')
        pathpatch.set_hatch('*')
        pathpatch.set_alpha(0.3)

        # plot contour line
        x, y = zip(*mypath.vertices)
        ax.plot(x, y, 'ro-')

        # set Axes
        ax.axis('equal')


    @staticmethod
    def path_wedge():
        from matplotlib.path import Path

        fig, ax = plt.subplots()

        verts = [(1, 1), (2, 1),
                 (1+np.cos(15/180*np.pi), 1+np.sin(15/180*np.pi)),
                 (1+np.sqrt(3)/2, 1+1/2),
                 (1, 1)]
        codes = [Path.MOVETO, Path.LINETO, Path.CURVE3, Path.LINETO, Path.LINETO]
        wedge_path = Path(vertices=verts, codes=codes)
        wedge_patch = mpl.patches.PathPatch(wedge_path)
        ax.add_patch(wedge_patch)
        ax.set(xlim=(0, 3), ylim=(0, 2))
        ax.scatter([1+np.cos(15/180*np.pi)], [1+np.sin(15/180*np.pi)], s=50)

class DemoHatch:

    from matplotlib.patches import Rectangle

    @staticmethod
    def hatche_rectangle(ax, h):
        ax.add_patch(DemoHatch.Rectangle((0, 0), 2, 2, fill=False, hatch=h, facecolor='gray'))
        ax.text(1, -0.5, f"' {h} '", size=15, ha="center")
        ax.axis('equal')
        ax.axis('off')

    @staticmethod
    def hatch_plot_each_pattern():
        fig, axs = plt.subplots(2, 5, constrained_layout=True, figsize=(6.4, 3.2))
        hatches = ['/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*']
        for ax, h in zip(axs.flat, hatches):
            DemoHatch.hatche_rectangle(ax, h)

    @staticmethod
    def hatch_repeat_pattern():
        fig, axs = plt.subplots(2, 5, constrained_layout=True, figsize=(6.4, 3.2))
        hatches = ['//', '\\\\', '||', '--', '++', 'xx', 'oo', 'OO', '..', '**']
        for ax, h in zip(axs.flat, hatches):
            DemoHatch.hatche_rectangle(ax, h)

    @staticmethod
    def hatch_multi_pattern():
        fig, axs = plt.subplots(2, 5, constrained_layout=True, figsize=(6.4, 3.2))
        hatches = ['/o', '\\|', '|*', '-\\', '+o', 'x*', 'o-', 'O|', 'O.', '*-']
        for ax, h in zip(axs.flat, hatches):
            DemoHatch.hatche_rectangle(ax, h)


class DemoAxis:

    @staticmethod
    def axis_twin():
        fig, ax1 = plt.subplots()

        x = np.linspace(1, 10, 10)
        y1 = 2 * x + 1
        y2 = x ** 2 + 1

        # draw x, y1 in ax1
        ax1.plot(x, y1, 'g--')
        plt.ylabel('$Y = 2*x + 1$')

        # create ax2 from ax1, draw x, y2 in ax2
        ax2 = ax1.twinx()
        ax2.plot(x, y2, 'b-')
        plt.ylabel('$Y = x^2 +1$ (ticks inverted)')
        # ax2.invert_yaxis()

    @staticmethod
    def axis_invert():
        x = np.linspace(1, 12, 12)
        y = np.log(x)

        fig, ax = plt.subplots()
        ax.invert_yaxis()
        ax.plot(x, y, 'g--')
        ax.set_ylabel('inverted ticks')
        # print(ax.yaxis_inverted())

        fig, ax = plt.subplots()
        ax.set(xlim=(12, 1))
        ax.plot(x, y, 'g--')
        ax.set_xlabel('inverted xaxis ticks by set xlim')


    @staticmethod
    def axis_xylim():
        fig, ax = plt.subplots(1, 3, figsize=(12, 4))
        fig.subplots_adjust(hspace=0.3, wspace=0.3)
        x = np.linspace(1, 12, 12)
        y = np.log(x)

        # unset xylim
        ax[0].plot(x, y, 'b--')
        ax[0].set_ylabel('no xylim set')

        # set xylim to less than data range
        ax[1].set_ylim(0, 10)
        ax[1].plot(x, y, 'b--')
        ax[1].set_ylabel('ylim = (0, 10)')

        # set xylim to invert data order
        ax[2].set_xlim(0, 5)
        ax[2].set_ylim(max(y), min(y))
        ax[2].plot(x, y, 'b--')
        ax[2].set_ylabel('xylim = (max(y), min(y))')

    @staticmethod
    def axis_arrow():
        """绘制带箭头的坐标轴，需要使用axisartist包"""
        # 使用axisartist.Subplot方法创建一个绘图区对象ax
        import mpl_toolkits.axisartist as axisartist
        fig = plt.figure()
        ax = axisartist.Subplot(fig, 111)
        fig.add_subplot(ax)     # add_axes(ax)

        # 绘制数据
        x = np.arange(0, 2*np.pi+0.1, 0.1)
        y = np.sin(x)
        ax.plot(x, y)

        # 通过set_visible方法设置绘图区所有坐标轴隐藏
        ax.axis[:].set_visible(False)

        # 使用ax.new_floating_axis添加新的坐标轴
        ax.axis["bottom"] = ax.new_floating_axis(0, 0)          # 轴的通过点为（0， 0）
        # 给x坐标轴加上箭头
        ax.axis["bottom"].set_axisline_style("->", size=3.0)

        # 添加y坐标轴，添加箭头
        ax.axis["left"] = ax.new_floating_axis(1, 0)            # 轴的通过点为（1， 0）
        ax.axis["left"].set_axisline_style("-|>", size=3.0)

        # 设置显示范围，可以间接移动坐标轴
        ax.set(xlim=(-1, 2*np.pi), ylim=(-2, 2))

        # 设置x、y轴上刻度显示方向
        # ax.axis["bottom"].set_axis_direction("top")
        # ax.axis["left"].set_axis_direction("right")

    @staticmethod
    def axis_spline_adjust():
        # 创建画板及子图
        fig, ax = plt.subplots()
        # 绘制数据
        ax.plot(range(10), np.sin(range(10)), 'g--')
        spines = ax.spines
        # 设置顶端轴线
        spines['top'].set_color('purple')
        spines['top'].set_linewidth(2)
        # 设置右边轴线，通过颜色控制产生无边框效果
        spines['right'].set_color('none')
        # 设置边界（主要针对数据范围）, 显示范围需要设置xlim/ylim
        ax.set(ylim=(-2, 1))
        spines['left'].set_bounds(-2, 1)
        spines['left'].set_linewidth(2)
        # 设置底端轴线
        spines['bottom'].set_position(('data', -2))
        spines['bottom'].set_linestyle(':')
        spines['bottom'].set_linewidth(5)

    @staticmethod
    def axis_spline_tocenter():
        fig, ax = plt.subplots()
        # 隐藏y轴右轴线
        ax.spines['right'].set_color('none')
        # 隐藏x轴上轴线
        ax.spines['top'].set_color('none')
        # x轴下轴线居中
        ax.spines['bottom'].set_position(('data', 0))
        # y轴下轴线移动至数据0点
        ax.spines['left'].set_position(('data', 0))
        # 设置刻度位置
        ax.xaxis.set_ticks_position('bottom')
        ax.yaxis.set_ticks_position('left')
        # 设置数据范围
        ax.set(xlim=(-1, 1), ylim=(-2, 2))

    @staticmethod
    def axis_scale():
        # 使用简单数据(直线 y = x）
        x = np.arange(0.1, 1, 0.01)
        y = x
        # linear scale，默认尺度类型
        fig, ax = plt.subplots(figsize=(10, 5))
        fig.subplots_adjust(wspace=0.3)
        plt.subplot(121)
        plt.plot(x, y, lw=3)
        plt.yscale('linear')
        plt.title('linear scale', fontdict={'fontsize': 24})
        plt.grid(True, lw=2)
        plt.xticks(fontsize=18)
        plt.yticks(fontsize=18)
        # log scale
        plt.subplot(122)
        plt.plot(x, y, lw=3)
        plt.yscale('log')
        plt.title('log scale', fontdict={'fontsize': 24})
        plt.grid(True, which='minor', axis='y', lw=1)
        plt.grid(True, which='major', lw=2)
        plt.xticks(fontsize=18)
        plt.yticks(fontsize=18)
        plt.minorticks_on()

    @staticmethod
    def axis_label():
        x = np.arange(0, 2*np.pi, 0.05)
        y1 = np.sin(5*x)*1/(x+1)
        y2 = np.cos(10*x)*1/(x+1)

        # plt.xylabel
        fig, ax = plt.subplots()
        ax.set_xlabel(
            xlabel=r'$y_{2}=\frac{sin(5x)}{1+x}$',
            labelpad=1,
            fontdict=dict(size=15, name='consolas')
            )
        ax.plot(x, y1)
        ax.set(xlim=(0, 2*np.pi), ylim=(-1, 1),
               title='set xlabel by plt.xlabel')

        # ax.set, ax.set_xylablel
        fig, ax = plt.subplots()
        ax.set_xlabel(
            xlabel=r'$y_{2}=\frac{cos(10x)}{1+x}$',
            labelpad=-50,
            fontdict=dict(size=20, name='SimHei')
        )
        ax.set(ylabel='set ylabel by ax.set(ylablel)',
               title='set xlabel by ax.set_xxx')
        ax.plot(x, y2)
        ax.set(xlim=(0, 2*np.pi), ylim=(-1, 1))


class DemoBoxplot:

    """
boxplot(x, notch=None, sym=None, vert=None, whis=None, positions=None, widths=None, patch_artist=None,
        bootstrap=None, usermedians=None, conf_intervals=None, meanline=None, showmeans=None,
        showcaps=None, showbox=None, showfliers=None, boxprops=None, labels=None, flierprops=None,
        medianprops=None, meanprops=None, capprops=None, whiskerprops=None, manage_ticks=True,
        autorange=False, zorder=None, *, data=None)
    Make a box and whisker plot.

    Make a box and whisker plot for each column of *x* or each
    vector in sequence *x*.  The box extends from the lower to
    upper quartile values of the data, with a line at the median.
    The whiskers extend from the box to show the range of the
    data.  Flier points are those past the end of the whiskers.

    Parameters
    ----------
    x : Array or a sequence of vectors.
        The input data.

    notch : bool, default: False
        Whether to draw a noteched box plot (`True`), or a rectangular box
        plot (`False`).  The notches represent the confidence interval (CI)
        around the median.  The documentation for *bootstrap* describes how
        the locations of the notches are computed.

        .. note::

            In cases where the values of the CI are less than the
            lower quartile or greater than the upper quartile, the
            notches will extend beyond the box, giving it a
            distinctive "flipped" appearance. This is expected
            behavior and consistent with other statistical
            visualization packages.

    sym : str, optional
        The default symbol for flier points.  An empty string ('') hides
        the fliers.  If `None`, then the fliers default to 'b+'.  More
        control is provided by the *flierprops* parameter.

    vert : bool, default: True
        If `True`, draws vertical boxes.
        If `False`, draw horizontal boxes.

    whis : float or (float, float), default: 1.5
        The position of the whiskers.

        If a float, the lower whisker is at the lowest datum above
        ``Q1 - whis*(Q3-Q1)``, and the upper whisker at the highest datum
        below ``Q3 + whis*(Q3-Q1)``, where Q1 and Q3 are the first and
        third quartiles.  The default value of ``whis = 1.5`` corresponds
        to Tukey's original definition of boxplots.

        If a pair of floats, they indicate the percentiles at which to
        draw the whiskers (e.g., (5, 95)).  In particular, setting this to
        (0, 100) results in whiskers covering the whole range of the data.
        "range" is a deprecated synonym for (0, 100).

        In the edge case where ``Q1 == Q3``, *whis* is automatically set
        to (0, 100) (cover the whole range of the data) if *autorange* is
        True.

        Beyond the whiskers, data are considered outliers and are plotted
        as individual points.

    bootstrap : int, optional
        Specifies whether to bootstrap the confidence intervals
        around the median for notched boxplots. If *bootstrap* is
        None, no bootstrapping is performed, and notches are
        calculated using a Gaussian-based asymptotic approximation
        (see McGill, R., Tukey, J.W., and Larsen, W.A., 1978, and
        Kendall and Stuart, 1967). Otherwise, bootstrap specifies
        the number of times to bootstrap the median to determine its
        95% confidence intervals. Values between 1000 and 10000 are
        recommended.

    usermedians : array-like, optional
        A 1D array-like of length ``len(x)``.  Each entry that is not
        `None` forces the value of the median for the corresponding
        dataset.  For entries that are `None`, the medians are computed
        by Matplotlib as normal.

    conf_intervals : array-like, optional
        A 2D array-like of shape ``(len(x), 2)``.  Each entry that is not
        None forces the location of the corresponding notch (which is
        only drawn if *notch* is `True`).  For entries that are `None`,
        the notches are computed by the method specified by the other
        parameters (e.g., *bootstrap*).

    positions : array-like, optional
        Sets the positions of the boxes. The ticks and limits are
        automatically set to match the positions. Defaults to
        ``range(1, N+1)`` where N is the number of boxes to be drawn.

    widths : float or array-like
        Sets the width of each box either with a scalar or a
        sequence. The default is 0.5, or ``0.15*(distance between
        extreme positions)``, if that is smaller.

    patch_artist : bool, default: False
        If `False` produces boxes with the Line2D artist. Otherwise,
        boxes and drawn with Patch artists.

    labels : sequence, optional
        Labels for each dataset (one per dataset).

    manage_ticks : bool, default: True
        If True, the tick locations and labels will be adjusted to match
        the boxplot positions.

    autorange : bool, default: False
        When `True` and the data are distributed such that the 25th and
        75th percentiles are equal, *whis* is set to (0, 100) such
        that the whisker ends are at the minimum and maximum of the data.

    meanline : bool, default: False
        If `True` (and *showmeans* is `True`), will try to render the
        mean as a line spanning the full width of the box according to
        *meanprops* (see below).  Not recommended if *shownotches* is also
        True.  Otherwise, means will be shown as points.

    zorder : float, default: ``Line2D.zorder = 2``
        Sets the zorder of the boxplot.

    Returns
    -------
    dict
      A dictionary mapping each component of the boxplot to a list
      of the `.Line2D` instances created. That dictionary has the
      following keys (assuming vertical boxplots):

      - ``boxes``: the main body of the boxplot showing the
        quartiles and the median's confidence intervals if
        enabled.

      - ``medians``: horizontal lines at the median of each box.

      - ``whiskers``: the vertical lines extending to the most
        extreme, non-outlier data points.

      - ``caps``: the horizontal lines at the ends of the
        whiskers.

      - ``fliers``: points representing data that extend beyond
        the whiskers (fliers).

      - ``means``: points or lines representing the means.

    Other Parameters
    ----------------
    showcaps : bool, default: True
        Show the caps on the ends of whiskers.
    showbox : bool, default: True
        Show the central box.
    showfliers : bool, default: True
        Show the outliers beyond the caps.
    showmeans : bool, default: False
        Show the arithmetic means.
    capprops : dict, default: None
        The style of the caps.
    boxprops : dict, default: None
        The style of the box.
    whiskerprops : dict, default: None
        The style of the whiskers.
    flierprops : dict, default: None
        The style of the fliers.
    medianprops : dict, default: None
        The style of the median.
    meanprops : dict, default: None
        The style of the mean.

    Notes
    -----


    .. note::
        In addition to the above described arguments, this function can take
        a *data* keyword argument. If such a *data* argument is given,
        every other argument can also be string ``s``, which is
        interpreted as ``data[s]`` (unless this raises an exception).

        Objects passed as **data** must support item access (``data[s]``) and
        membership syntax (``s in data``).
    """

    @staticmethod
    def test_usermedians():
        import pandas as pd
        fig, ax = plt.subplots(1, 2)

        # data
        x = np.array([1, 2, 2, 1, 3, 2, 3, 3, 3, 5, 4, 6, 4, 6.6, -1.6])
        r = pd.Series(x).describe()
        data_upper = r['75%'] + 1.5*(r['75%']-r['25%'])
        data_lower = r['25%'] - 1.5*(r['75%']-r['25%'])
        boxtop = max([v for v in x if v < data_upper])
        boxbot = min([v for v in x if v > data_lower])
        print(r)

        # settings
        notch = [False, True]
        usermedians = [None, 1.6, 4.5]
        showmeans = True
        ticks = [
            ['notch=True\nusermedian=None', 'notch=True\nusermedian=1.6', 'notch=True\nusermedian=4.5'],
            ['notch=False\nusermedian=None', 'notch=False\nusermedian=1.6', 'notch=False\nusermedian=4.5'],
            ['notch=True\nusermedian=None', 'notch=True\nusermedian=1.6', 'notch=True\nusermedian=4.5'],
        ]
        realmedian = 'realmedian={}'.format(np.median(x))
        # plot
        result = [None, None]
        for j in range(2):
            result[j] = ax[j].boxplot(
                x=[x, x, x],
                notch=notch[j],
                sym='go',
                usermedians=usermedians,
                showmeans=showmeans,
                widths=0.6,
                whiskerprops={'linestyle': '--'},
                medianprops={'color': 'green', 'linestyle': '--'}
                )
            # text medians
            ax[j].text(x=1, y=np.median(x), s='{:2.2f}'.format(np.median(x)), color='r')
            ax[j].text(x=2, y=usermedians[1], s='{:2.2f}'.format(usermedians[1]))
            ax[j].text(x=3, y=usermedians[2], s='{:2.2f}'.format(usermedians[2]))
            # text top and bottom line of box
            ax[j].text(x=1, y=boxtop+0.05, s='{:2.2f}'.format(boxtop), color='purple')
            ax[j].text(x=1, y=boxbot-0.30, s='{:2.2f}'.format(boxbot), color='purple')
            # set xticklabels
            ax[j].set(xticklabels=ticks[j])

        return result

    @staticmethod
    def test_conf_intervals(x=None):
        fig, ax = plt.subplots(3, 1)

        # data
        if x is None:
            dime = 3
            x = np.random.random((10, dime))

        # settings
        notch = [True, False, True]
        usermedians = [0.5, None, 1]
        showmeans = True
        bootstrap = 5
        conf_intervals = [np.array([[0.4, 0.4], None, None]),
                          np.array([[0.2, 0.6], [0.1, 0.4], [0.4, 0.6]]),
                          np.array([[0.5, 0.7], [0.2, 0.4], [0.4, 0.6]]),
                          ]
        ticks = [['[0.4, 0.4]', 'None', 'None'],
                 ['[0.2, 0.6]', '[0.1, 0.4]', '[0.4, 0.6]'],
                 ['[0.2, 0.6]', '[0.1, 0.4]', '[0.4, 0.6]']]

        # plot
        for j in range(3):
            ax[j].boxplot(
                x,
                notch=notch[j],
                sym='go',
                usermedians=usermedians,
                showmeans=showmeans,
                bootstrap=bootstrap,
                conf_intervals=conf_intervals[j]
                )
            ax[j].set(xticklabels=ticks[j])

        return x


class DemoSpines:

    # Spine
    """
class Spine(matplotlib.patches.Patch)
 |
    Spine(axes, spine_type, path, **kwargs)
 |
 |  An axis spine -- the line noting the data area boundaries.
 |
 |  Spines are the lines connecting the axis tick marks and noting the
 |  boundaries of the data area. They can be placed at arbitrary
 |  positions. See `~.Spine.set_position` for more information.
 |
 |  The default position is ``('outward', 0)``.
 |
 |  Spines are subclasses of `.Patch`, and inherit much of their behavior.
 |
 |  Spines draw a line, a circle, or an arc depending if
 |  `~.Spine.set_patch_line`, `~.Spine.set_patch_circle`, or
 |  `~.Spine.set_patch_arc` has been called. Line-like is the default.
 |
 |  Method resolution order:
 |      Spine
 |      matplotlib.patches.Patch
 |      matplotlib.artist.Artist
 |      builtins.object
 |
 |  Methods defined here:
 |
 |  __init__(self, axes, spine_type, path, **kwargs)
 |      Parameters
 |      ----------
 |      axes : `~matplotlib.axes.Axes`
 |          The `~.axes.Axes` instance containing the spine.
 |      spine_type : str
 |          The spine type.
 |      path : `~matplotlib.path.Path`
 |          The `.Path` instance used to draw the spine.
 |
 |      Other Parameters
 |      ----------------
 |      **kwargs
 |          Valid keyword arguments are:
 |
 |          Properties:
 |          agg_filter: a filter function, which takes a (m, n, 3) float array and a dpi value, and returns a (m, n, 3) array
 |          alpha: float or None
 |          animated: bool
 |          antialiased or aa: unknown
 |          capstyle: {'butt', 'round', 'projecting'}
 |          clip_box: `.Bbox`
 |          clip_on: bool
 |          clip_path: Patch or (Path, Transform) or None
 |          color: color
 |          contains: unknown
 |          edgecolor or ec: color or None or 'auto'
 |          facecolor or fc: color or None
 |          figure: `.Figure`
 |          fill: bool
 |          gid: str
 |          hatch: {'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
 |          in_layout: bool
 |          joinstyle: {'miter', 'round', 'bevel'}
 |          label: object
 |          linestyle or ls: {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
 |          linewidth or lw: float or None
 |          path_effects: `.AbstractPathEffect`
 |          picker: None or bool or callable
 |          rasterized: bool or None
 |          sketch_params: (scale: float, length: float, randomness: float)
 |          snap: bool or None
 |          transform: `.Transform`
 |          url: str
 |          visible: bool
 |          zorder: float
 |
 |  __str__(self)
 |      Return str(self).
 |
 |  cla(self)
 |      Clear the current spine.
 |
 |  draw(self, renderer)
 |      Draw the Artist (and its children) using the given renderer.
 |
 |      This has no effect if the artist is not visible (`.Artist.get_visible`
 |      returns False).
 |
 |      Parameters
 |      ----------
 |      renderer : `.RendererBase` subclass.
 |
 |      Notes
 |      -----
 |      This method is overridden in the Artist subclasses.
 |
 |  get_bounds(self)
 |      Get the bounds of the spine.
 |
 |  get_patch_transform(self)
 |      Return the `~.transforms.Transform` instance mapping patch coordinates
 |      to data coordinates.
 |
 |      For example, one may define a patch of a circle which represents a
 |      radius of 5 by providing coordinates for a unit circle, and a
 |      transform which scales the coordinates (the patch coordinate) by 5.
 |
 |  get_path(self)
 |      Return the path of this patch.
 |
 |  get_position(self)
 |      Return the spine position.
 |
 |  get_smart_bounds(self)
 |      [*Deprecated*] Return whether the spine has smart bounds.
 |
 |      Notes
 |      -----
 |      .. deprecated:: 3.2
 |
 |  get_spine_transform(self)
 |      Return the spine transform.
 |
 |  get_window_extent(self, renderer=None)
 |      Return the window extent of the spines in display space, including
 |      padding for ticks (but not their labels)
 |
 |      See Also
 |      --------
 |      matplotlib.axes.Axes.get_tightbbox
 |      matplotlib.axes.Axes.get_window_extent
 |
 |  register_axis(self, axis)
 |      Register an axis.
 |
 |      An axis should be registered with its corresponding spine from
 |      the Axes instance. This allows the spine to clear any axis
 |      properties when needed.
 |
 |  set_bounds(self, low=None, high=None)
 |      Set the spine bounds.
 |
 |      Parameters
 |      ----------
 |      low : float or None, optional
 |          The lower spine bound. Passing *None* leaves the limit unchanged.
 |
 |          The bounds may also be passed as the tuple (*low*, *high*) as the
 |          first positional argument.
 |
 |          .. ACCEPTS: (low: float, high: float)
 |
 |      high : float or None, optional
 |          The higher spine bound. Passing *None* leaves the limit unchanged.
 |
 |  set_color(self, c)
 |      Set the edgecolor.
 |
 |      Parameters
 |      ----------
 |      c : color
 |
 |      Notes
 |      -----
 |      This method does not modify the facecolor (which defaults to "none"),
 |      unlike the `.Patch.set_color` method defined in the parent class.  Use
 |      `.Patch.set_facecolor` to set the facecolor.
 |
 |  set_patch_arc(self, center, radius, theta1, theta2)
 |      Set the spine to be arc-like.
 |
 |  set_patch_circle(self, center, radius)
 |      Set the spine to be circular.
 |
 |  set_patch_line(self)
 |      Set the spine to be linear.
 |
 |  set_position(self, position)
 |      Set the position of the spine.
 |
 |      Spine position is specified by a 2 tuple of (position type,
 |      amount). The position types are:
 |
 |      * 'outward': place the spine out from the data area by the specified
 |        number of points. (Negative values place the spine inwards.)
 |      * 'axes': place the spine at the specified Axes coordinate (0 to 1).
 |      * 'data': place the spine at the specified data coordinate.
 |
 |      Additionally, shorthand notations define a special positions:
 |
 |      * 'center' -> ('axes', 0.5)
 |      * 'zero' -> ('data', 0.0)
 |
 |  set_smart_bounds(self, value)
 |      [*Deprecated*] Set the spine and associated axis to have smart bounds.
 |
 |      Notes
 |      -----
 |      .. deprecated:: 3.2
 |
 |  ----------------------------------------------------------------------
 |  Class methods defined here:
 |
 |  arc_spine(axes, spine_type, center, radius, theta1, theta2, **kwargs) from builtins.type
 |      Create and return an arc `Spine`.
 |
 |  circular_spine(axes, center, radius, **kwargs) from builtins.type
 |      Create and return a circular `Spine`.
 |
 |  linear_spine(axes, spine_type, **kwargs) from builtins.type
 |      Create and return a linear `Spine`.
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from matplotlib.patches.Patch:
 |
 |  contains(self, mouseevent, radius=None)
 |      Test whether the mouse event occurred in the patch.
 |
 |      Returns
 |      -------
 |      (bool, empty dict)
 |
 |  contains_point(self, point, radius=None)
 |      Return whether the given point is inside the patch.
 |
 |      Parameters
 |      ----------
 |      point : (float, float)
 |          The point (x, y) to check, in target coordinates of
 |          ``self.get_transform()``. These are display coordinates for patches
 |          that are added to a figure or axes.
 |      radius : float, optional
 |          Add an additional margin on the patch in target coordinates of
 |          ``self.get_transform()``. See `.Path.contains_point` for further
 |          details.
 |
 |      Returns
 |      -------
 |      bool
 |
 |      Notes
 |      -----
 |      The proper use of this method depends on the transform of the patch.
 |      Isolated patches do not have a transform. In this case, the patch
 |      creation coordinates and the point coordinates match. The following
 |      example checks that the center of a circle is within the circle
 |
 |      >>> center = 0, 0
 |      >>> c = Circle(center, radius=1)
 |      >>> c.contains_point(center)
 |      True
 |
 |      The convention of checking against the transformed patch stems from
 |      the fact that this method is predominantly used to check if display
 |      coordinates (e.g. from mouse events) are within the patch. If you want
 |      to do the above check with data coordinates, you have to properly
 |      transform them first:
 |
 |      >>> center = 0, 0
 |      >>> c = Circle(center, radius=1)
 |      >>> plt.gca().add_patch(c)
 |      >>> transformed_center = c.get_transform().transform(center)
 |      >>> c.contains_point(transformed_center)
 |      True
 |
 |  contains_points(self, points, radius=None)
 |      Return whether the given points are inside the patch.
 |
 |      Parameters
 |      ----------
 |      points : (N, 2) array
 |          The points to check, in target coordinates of
 |          ``self.get_transform()``. These are display coordinates for patches
 |          that are added to a figure or axes. Columns contain x and y values.
 |      radius : float, optional
 |          Add an additional margin on the patch in target coordinates of
 |          ``self.get_transform()``. See `.Path.contains_point` for further
 |          details.
 |
 |      Returns
 |      -------
 |      length-N bool array
 |
 |      Notes
 |      -----
 |      The proper use of this method depends on the transform of the patch.
 |      See the notes on `.Patch.contains_point`.
 |
 |  get_aa(self)
 |      Alias for `get_antialiased`.
 |
 |  get_antialiased(self)
 |      Return whether antialiasing is used for drawing.
 |
 |  get_capstyle(self)
 |      Return the capstyle.
 |
 |  get_data_transform(self)
 |      Return the `~.transforms.Transform` mapping data coordinates to
 |      physical coordinates.
 |
 |  get_ec(self)
 |      Alias for `get_edgecolor`.
 |
 |  get_edgecolor(self)
 |      Return the edge color.
 |
 |  get_extents(self)
 |      Return the `Patch`'s axis-aligned extents as a `~.transforms.Bbox`.
 |
 |  get_facecolor(self)
 |      Return the face color.
 |
 |  get_fc(self)
 |      Alias for `get_facecolor`.
 |
 |  get_fill(self)
 |      Return whether the patch is filled.
 |
 |  get_hatch(self)
 |      Return the hatching pattern.
 |
 |  get_joinstyle(self)
 |      Return the joinstyle.
 |
 |  get_linestyle(self)
 |      Return the linestyle.
 |
 |  get_linewidth(self)
 |      Return the line width in points.
 |
 |  get_ls(self)
 |      Alias for `get_linestyle`.
 |
 |  get_lw(self)
 |      Alias for `get_linewidth`.
 |
 |  get_transform(self)
 |      Return the `~.transforms.Transform` applied to the `Patch`.
 |
 |  get_verts(self)
 |      Return a copy of the vertices used in this patch.
 |
 |      If the patch contains Bezier curves, the curves will be interpolated by
 |      line segments.  To access the curves as curves, use `get_path`.
 |
 |  set_aa(self, aa)
 |      Alias for `set_antialiased`.
 |
 |  set_alpha(self, alpha)
 |      Set the alpha value used for blending - not supported on all backends.
 |
 |      Parameters
 |      ----------
 |      alpha : float or None
 |
 |  set_antialiased(self, aa)
 |      Set whether to use antialiased rendering.
 |
 |      Parameters
 |      ----------
 |      b : bool or None
 |
 |  set_capstyle(self, s)
 |      Set the capstyle.
 |
 |      Parameters
 |      ----------
 |      s : {'butt', 'round', 'projecting'}
 |
 |  set_ec(self, color)
 |      Alias for `set_edgecolor`.
 |
 |  set_edgecolor(self, color)
 |      Set the patch edge color.
 |
 |      Parameters
 |      ----------
 |      color : color or None or 'auto'
 |
 |  set_facecolor(self, color)
 |      Set the patch face color.
 |
 |      Parameters
 |      ----------
 |      color : color or None
 |
 |  set_fc(self, color)
 |      Alias for `set_facecolor`.
 |
 |  set_fill(self, b)
 |      Set whether to fill the patch.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_hatch(self, hatch)
 |      Set the hatching pattern.
 |
 |      *hatch* can be one of::
 |
 |        /   - diagonal hatching
 |        \   - back diagonal
 |        |   - vertical
 |        -   - horizontal
 |        +   - crossed
 |        x   - crossed diagonal
 |        o   - small circle
 |        O   - large circle
 |        .   - dots
 |        *   - stars
 |
 |      Letters can be combined, in which case all the specified
 |      hatchings are done.  If same letter repeats, it increases the
 |      density of hatching of that pattern.
 |
 |      Hatching is supported in the PostScript, PDF, SVG and Agg
 |      backends only.
 |
 |      Parameters
 |      ----------
 |      hatch : {'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
 |
 |  set_joinstyle(self, s)
 |      Set the joinstyle.
 |
 |      Parameters
 |      ----------
 |      s : {'miter', 'round', 'bevel'}
 |
 |  set_linestyle(self, ls)
 |      Set the patch linestyle.
 |
 |      ===========================   =================
 |      linestyle                     description
 |      ===========================   =================
 |      ``'-'`` or ``'solid'``        solid line
 |      ``'--'`` or  ``'dashed'``     dashed line
 |      ``'-.'`` or  ``'dashdot'``    dash-dotted line
 |      ``':'`` or ``'dotted'``       dotted line
 |      ===========================   =================
 |
 |      Alternatively a dash tuple of the following form can be provided::
 |
 |          (offset, onoffseq)
 |
 |      where ``onoffseq`` is an even length tuple of on and off ink in points.
 |
 |      Parameters
 |      ----------
 |      ls : {'-', '--', '-.', ':', '', (offset, on-off-seq), ...}
 |          The line style.
 |
 |  set_linewidth(self, w)
 |      Set the patch linewidth in points.
 |
 |      Parameters
 |      ----------
 |      w : float or None
 |
 |  set_ls(self, ls)
 |      Alias for `set_linestyle`.
 |
 |  set_lw(self, w)
 |      Alias for `set_linewidth`.
 |
 |  update_from(self, other)
 |      Copy properties from *other* to *self*.
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from matplotlib.patches.Patch:
 |
 |  fill
 |      Return whether the patch is filled.
 |
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from matplotlib.patches.Patch:
 |
 |  validCap = ('butt', 'round', 'projecting')
 |
 |  validJoin = ('miter', 'round', 'bevel')
 |
 |  zorder = 1
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from matplotlib.artist.Artist:
 |
 |  __getstate__(self)
 |
 |  add_callback(self, func)
 |      Add a callback function that will be called whenever one of the
 |      `.Artist`'s properties changes.
 |
 |      Parameters
 |      ----------
 |      func : callable
 |          The callback function. It must have the signature::
 |
 |              def func(artist: Artist) -> Any
 |
 |          where *artist* is the calling `.Artist`. Return values may exist
 |          but are ignored.
 |
 |      Returns
 |      -------
 |      int
 |          The observer id associated with the callback. This id can be
 |          used for removing the callback with `.remove_callback` later.
 |
 |      See Also
 |      --------
 |      remove_callback
 |
 |  convert_xunits(self, x)
 |      Convert *x* using the unit type of the xaxis.
 |
 |      If the artist is not in contained in an Axes or if the xaxis does not
 |      have units, *x* itself is returned.
 |
 |  convert_yunits(self, y)
 |      Convert *y* using the unit type of the yaxis.
 |
 |      If the artist is not in contained in an Axes or if the yaxis does not
 |      have units, *y* itself is returned.
 |
 |  findobj(self, match=None, include_self=True)
 |      Find artist objects.
 |
 |      Recursively find all `.Artist` instances contained in the artist.
 |
 |      Parameters
 |      ----------
 |      match
 |          A filter criterion for the matches. This can be
 |
 |          - *None*: Return all objects contained in artist.
 |          - A function with signature ``def match(artist: Artist) -> bool``.
 |            The result will only contain artists for which the function
 |            returns *True*.
 |          - A class instance: e.g., `.Line2D`. The result will only contain
 |            artists of this class or its subclasses (``isinstance`` check).
 |
 |      include_self : bool
 |          Include *self* in the list to be checked for a match.
 |
 |      Returns
 |      -------
 |      list of `.Artist`
 |
 |  format_cursor_data(self, data)
 |      Return a string representation of *data*.
 |
 |      .. note::
 |          This method is intended to be overridden by artist subclasses.
 |          As an end-user of Matplotlib you will most likely not call this
 |          method yourself.
 |
 |      The default implementation converts ints and floats and arrays of ints
 |      and floats into a comma-separated string enclosed in square brackets.
 |
 |      See Also
 |      --------
 |      get_cursor_data
 |
 |  get_agg_filter(self)
 |      Return filter function to be used for agg filter.
 |
 |  get_alpha(self)
 |      Return the alpha value used for blending - not supported on all
 |      backends.
 |
 |  get_animated(self)
 |      Return whether the artist is animated.
 |
 |  get_children(self)
 |      Return a list of the child `.Artist`\s of this `.Artist`.
 |
 |  get_clip_box(self)
 |      Return the clipbox.
 |
 |  get_clip_on(self)
 |      Return whether the artist uses clipping.
 |
 |  get_clip_path(self)
 |      Return the clip path.
 |
 |  get_contains(self)
 |      [*Deprecated*] Return the custom contains function of the artist if set, or *None*.
 |
 |      See Also
 |      --------
 |      set_contains
 |
 |      Notes
 |      -----
 |      .. deprecated:: 3.3
 |
 |  get_cursor_data(self, event)
 |      Return the cursor data for a given event.
 |
 |      .. note::
 |          This method is intended to be overridden by artist subclasses.
 |          As an end-user of Matplotlib you will most likely not call this
 |          method yourself.
 |
 |      Cursor data can be used by Artists to provide additional context
 |      information for a given event. The default implementation just returns
 |      *None*.
 |
 |      Subclasses can override the method and return arbitrary data. However,
 |      when doing so, they must ensure that `.format_cursor_data` can convert
 |      the data to a string representation.
 |
 |      The only current use case is displaying the z-value of an `.AxesImage`
 |      in the status bar of a plot window, while moving the mouse.
 |
 |      Parameters
 |      ----------
 |      event : `matplotlib.backend_bases.MouseEvent`
 |
 |      See Also
 |      --------
 |      format_cursor_data
 |
 |  get_figure(self)
 |      Return the `.Figure` instance the artist belongs to.
 |
 |  get_gid(self)
 |      Return the group id.
 |
 |  get_in_layout(self)
 |      Return boolean flag, ``True`` if artist is included in layout
 |      calculations.
 |
 |      E.g. :doc:`/tutorials/intermediate/constrainedlayout_guide`,
 |      `.Figure.tight_layout()`, and
 |      ``fig.savefig(fname, bbox_inches='tight')``.
 |
 |  get_label(self)
 |      Return the label used for this artist in the legend.
 |
 |  get_path_effects(self)
 |
 |  get_picker(self)
 |      Return the picking behavior of the artist.
 |
 |      The possible values are described in `.set_picker`.
 |
 |      See Also
 |      --------
 |      set_picker, pickable, pick
 |
 |  get_rasterized(self)
 |      Return whether the artist is to be rasterized.
 |
 |  get_sketch_params(self)
 |      Return the sketch parameters for the artist.
 |
 |      Returns
 |      -------
 |      tuple or None
 |
 |          A 3-tuple with the following elements:
 |
 |          - *scale*: The amplitude of the wiggle perpendicular to the
 |            source line.
 |          - *length*: The length of the wiggle along the line.
 |          - *randomness*: The scale factor by which the length is
 |            shrunken or expanded.
 |
 |          Returns *None* if no sketch parameters were set.
 |
 |  get_snap(self)
 |      Return the snap setting.
 |
 |      See `.set_snap` for details.
 |
 |  get_tightbbox(self, renderer)
 |      Like `.Artist.get_window_extent`, but includes any clipping.
 |
 |      Parameters
 |      ----------
 |      renderer : `.RendererBase` subclass
 |          renderer that will be used to draw the figures (i.e.
 |          ``fig.canvas.get_renderer()``)
 |
 |      Returns
 |      -------
 |      `.Bbox`
 |          The enclosing bounding box (in figure pixel coordinates).
 |
 |  get_transformed_clip_path_and_affine(self)
 |      Return the clip path with the non-affine part of its
 |      transformation applied, and the remaining affine part of its
 |      transformation.
 |
 |  get_url(self)
 |      Return the url.
 |
 |  get_visible(self)
 |      Return the visibility.
 |
 |  get_zorder(self)
 |      Return the artist's zorder.
 |
 |  have_units(self)
 |      Return *True* if units are set on any axis.
 |
 |  is_transform_set(self)
 |      Return whether the Artist has an explicitly set transform.
 |
 |      This is *True* after `.set_transform` has been called.
 |
 |  pchanged(self)
 |      Call all of the registered callbacks.
 |
 |      This function is triggered internally when a property is changed.
 |
 |      See Also
 |      --------
 |      add_callback
 |      remove_callback
 |
 |  pick(self, mouseevent)
 |      Process a pick event.
 |
 |      Each child artist will fire a pick event if *mouseevent* is over
 |      the artist and the artist has picker set.
 |
 |      See Also
 |      --------
 |      set_picker, get_picker, pickable
 |
 |  pickable(self)
 |      Return whether the artist is pickable.
 |
 |      See Also
 |      --------
 |      set_picker, get_picker, pick
 |
 |  properties(self)
 |      Return a dictionary of all the properties of the artist.
 |
 |  remove(self)
 |      Remove the artist from the figure if possible.
 |
 |      The effect will not be visible until the figure is redrawn, e.g.,
 |      with `.FigureCanvasBase.draw_idle`.  Call `~.axes.Axes.relim` to
 |      update the axes limits if desired.
 |
 |      Note: `~.axes.Axes.relim` will not see collections even if the
 |      collection was added to the axes with *autolim* = True.
 |
 |      Note: there is no support for removing the artist's legend entry.
 |
 |  remove_callback(self, oid)
 |      Remove a callback based on its observer id.
 |
 |      See Also
 |      --------
 |      add_callback
 |
 |  set(self, **kwargs)
 |      A property batch setter.  Pass *kwargs* to set properties.
 |
 |  set_agg_filter(self, filter_func)
 |      Set the agg filter.
 |
 |      Parameters
 |      ----------
 |      filter_func : callable
 |          A filter function, which takes a (m, n, 3) float array and a dpi
 |          value, and returns a (m, n, 3) array.
 |
 |          .. ACCEPTS: a filter function, which takes a (m, n, 3) float array
 |              and a dpi value, and returns a (m, n, 3) array
 |
 |  set_animated(self, b)
 |      Set the artist's animation state.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_clip_box(self, clipbox)
 |      Set the artist's clip `.Bbox`.
 |
 |      Parameters
 |      ----------
 |      clipbox : `.Bbox`
 |
 |  set_clip_on(self, b)
 |      Set whether the artist uses clipping.
 |
 |      When False artists will be visible outside of the axes which
 |      can lead to unexpected results.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_clip_path(self, path, transform=None)
 |      Set the artist's clip path.
 |
 |      Parameters
 |      ----------
 |      path : `.Patch` or `.Path` or `.TransformedPath` or None
 |          The clip path. If given a `.Path`, *transform* must be provided as
 |          well. If *None*, a previously set clip path is removed.
 |      transform : `~matplotlib.transforms.Transform`, optional
 |          Only used if *path* is a `.Path`, in which case the given `.Path`
 |          is converted to a `.TransformedPath` using *transform*.
 |
 |      Notes
 |      -----
 |      For efficiency, if *path* is a `.Rectangle` this method will set the
 |      clipping box to the corresponding rectangle and set the clipping path
 |      to ``None``.
 |
 |      For technical reasons (support of `~.Artist.set`), a tuple
 |      (*path*, *transform*) is also accepted as a single positional
 |      parameter.
 |
 |      .. ACCEPTS: Patch or (Path, Transform) or None
 |
 |  set_contains(self, picker)
 |      [*Deprecated*] Define a custom contains syntax for the artist.
 |
 |      The provided callable replaces the default `.contains` method
 |      of the artist.
 |
 |      Parameters
 |      ----------
 |      picker : callable
 |          A custom picker function to evaluate if an event is within the
 |          artist. The function must have the signature::
 |
 |              def contains(artist: Artist, event: MouseEvent) -> bool, dict
 |
 |          that returns:
 |
 |          - a bool indicating if the event is within the artist
 |          - a dict of additional information. The dict should at least
 |            return the same information as the default ``contains()``
 |            implementation of the respective artist, but may provide
 |            additional information.
 |
 |      Notes
 |      -----
 |      .. deprecated:: 3.3
 |
 |  set_figure(self, fig)
 |      Set the `.Figure` instance the artist belongs to.
 |
 |      Parameters
 |      ----------
 |      fig : `.Figure`
 |
 |  set_gid(self, gid)
 |      Set the (group) id for the artist.
 |
 |      Parameters
 |      ----------
 |      gid : str
 |
 |  set_in_layout(self, in_layout)
 |      Set if artist is to be included in layout calculations,
 |      E.g. :doc:`/tutorials/intermediate/constrainedlayout_guide`,
 |      `.Figure.tight_layout()`, and
 |      ``fig.savefig(fname, bbox_inches='tight')``.
 |
 |      Parameters
 |      ----------
 |      in_layout : bool
 |
 |  set_label(self, s)
 |      Set a label that will be displayed in the legend.
 |
 |      Parameters
 |      ----------
 |      s : object
 |          *s* will be converted to a string by calling `str`.
 |
 |  set_path_effects(self, path_effects)
 |      Set the path effects.
 |
 |      Parameters
 |      ----------
 |      path_effects : `.AbstractPathEffect`
 |
 |  set_picker(self, picker)
 |      Define the picking behavior of the artist.
 |
 |      Parameters
 |      ----------
 |      picker : None or bool or callable
 |          This can be one of the following:
 |
 |          - *None*: Picking is disabled for this artist (default).
 |
 |          - A boolean: If *True* then picking will be enabled and the
 |            artist will fire a pick event if the mouse event is over
 |            the artist.
 |
 |          - A function: If picker is callable, it is a user supplied
 |            function which determines whether the artist is hit by the
 |            mouse event::
 |
 |              hit, props = picker(artist, mouseevent)
 |
 |            to determine the hit syntax.  if the mouse event is over the
 |            artist, return *hit=True* and props is a dictionary of
 |            properties you want added to the PickEvent attributes.
 |
 |          - *deprecated*: For `.Line2D` only, *picker* can also be a float
 |            that sets the tolerance for checking whether an event occurred
 |            "on" the line; this is deprecated.  Use `.Line2D.set_pickradius`
 |            instead.
 |
 |  set_rasterized(self, rasterized)
 |      Force rasterized (bitmap) drawing in vector backend output.
 |
 |      Defaults to None, which implies the backend's default behavior.
 |
 |      Parameters
 |      ----------
 |      rasterized : bool or None
 |
 |  set_sketch_params(self, scale=None, length=None, randomness=None)
 |      Sets the sketch parameters.
 |
 |      Parameters
 |      ----------
 |      scale : float, optional
 |          The amplitude of the wiggle perpendicular to the source
 |          line, in pixels.  If scale is `None`, or not provided, no
 |          sketch filter will be provided.
 |      length : float, optional
 |           The length of the wiggle along the line, in pixels
 |           (default 128.0)
 |      randomness : float, optional
 |          The scale factor by which the length is shrunken or
 |          expanded (default 16.0)
 |
 |          .. ACCEPTS: (scale: float, length: float, randomness: float)
 |
 |  set_snap(self, snap)
 |      Set the snapping behavior.
 |
 |      Snapping aligns positions with the pixel grid, which results in
 |      clearer images. For example, if a black line of 1px width was
 |      defined at a position in between two pixels, the resulting image
 |      would contain the interpolated value of that line in the pixel grid,
 |      which would be a grey value on both adjacent pixel positions. In
 |      contrast, snapping will move the line to the nearest integer pixel
 |      value, so that the resulting image will really contain a 1px wide
 |      black line.
 |
 |      Snapping is currently only supported by the Agg and MacOSX backends.
 |
 |      Parameters
 |      ----------
 |      snap : bool or None
 |          Possible values:
 |
 |          - *True*: Snap vertices to the nearest pixel center.
 |          - *False*: Do not modify vertex positions.
 |          - *None*: (auto) If the path contains only rectilinear line
 |            segments, round to the nearest pixel center.
 |
 |  set_transform(self, t)
 |      Set the artist transform.
 |
 |      Parameters
 |      ----------
 |      t : `.Transform`
 |
 |  set_url(self, url)
 |      Set the url for the artist.
 |
 |      Parameters
 |      ----------
 |      url : str
 |
 |  set_visible(self, b)
 |      Set the artist's visibility.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_zorder(self, level)
 |      Set the zorder for the artist.  Artists with lower zorder
 |      values are drawn first.
 |
 |      Parameters
 |      ----------
 |      level : float
 |
 |  update(self, props)
 |      Update this artist's properties from the dict *props*.
 |
 |      Parameters
 |      ----------
 |      props : dict
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from matplotlib.artist.Artist:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)
 |
 |  axes
 |      The `~.axes.Axes` instance the artist resides in, or *None*.
 |
 |  mouseover
 |      If this property is set to *True*, the artist will be queried for
 |      custom context information when the mouse cursor moves over it.
 |
 |      See also :meth:`get_cursor_data`, :class:`.ToolCursorPosition` and
 |      :class:`.NavigationToolbar2`.
 |
 |  stale
 |      Whether the artist is 'stale' and needs to be re-drawn for the output
 |      to match the internal state of the artist.
 |
 |  sticky_edges
 |      ``x`` and ``y`` sticky edge lists for autoscaling.
 |
 |      When performing autoscaling, if a data limit coincides with a value in
 |      the corresponding sticky_edges list, then no margin will be added--the
 |      view limit "sticks" to the edge. A typical use case is histograms,
 |      where one usually expects no margin on the bottom edge (0) of the
 |      histogram.
 |
 |      This attribute cannot be assigned to; however, the ``x`` and ``y``
 |      lists can be modified in place as needed.
 |
 |      Examples
 |      --------
 |      >>> artist.sticky_edges.x[:] = (xmin, xmax)
 |      >>> artist.sticky_edges.y[:] = (ymin, ymax)


    """

    @staticmethod
    def get_spines():
        fig, ax = plt.subplots()
        print(ax.spines)
        print(ax.spines['left'])

    @staticmethod
    def set_spines_properties(c=None):
        fig, ax = plt.subplots()

        # plot data
        ax.plot(range(10), np.sin(range(10)), 'g--')

        # set color, 'none' means no display
        spines = ax.spines

        # set top spine
        spines['top'].set_color('purple')
        spines['top'].set_linewidth(2)

        spines['right'].set_color('none')

        # set bounds means value range, lim means display range
        ax.set(ylim=(-2, 1))
        spines['left'].set_bounds(-2, 1)
        spines['left'].set_linewidth(2)

        # set position of bottom axis line
        spines['bottom'].set_position(('data', -2))
        spines['bottom'].set_linestyle(':')
        spines['bottom'].set_linewidth(5)

        # set frame on by False, but ticks and labels remain to display
        # ax.set_frame_on(False)

    @staticmethod
    def spines_set_xxx():
        """
        通过axes.spines[axis].set_xxx, 调整坐标轴轴线
        axis： bottom, top, left, right分别为x/y轴的下、上、左、右轴线
        set_position: 设置轴线的位置
        set_color: 设置轴线的颜色
        set_bounds: 设置轴线的显示范围
        """
        # 创建画板、子图
        fig, ax = plt.subplots()
        # 绘制数据
        x = np.arange(-np.pi, np.pi, 0.1)
        y = np.sin(x)
        ax.plot(x, y, 'bo--')
        # 设置左边和底端轴线位置
        ax.spines['bottom'].set_position(('data', 0))
        ax.spines['left'].set_position(('data', 0))
        # 隐含顶端和右边轴线
        ax.spines['top'].set_color('none')
        ax.spines['right'].set_color('none')
        # 设置边界，限制轴线显示， 但不影响刻度显示
        ax.spines['left'].set_bounds(low=-1.5, high=2)
        ax.set(ylim=(-2, 2))


class DemoText:

    """
class Text(matplotlib.artist.Artist)
 |  Text(x=0, y=0, text='', color=None, verticalalignment='baseline', horizontalalignment='left',
 multialignment=None, fontproperties=None, rotation=None, linespacing=None, rotation_mode=None,
 usetex=None, wrap=False, **kwargs)
 |
 |  Handle storing and drawing of text in window or data coordinates.
 |
 |  Method resolution order:
 |      Text
 |      matplotlib.artist.Artist
 |      builtins.object
 |
 |  Methods defined here:
 |
 |  __getstate__(self)
 |
 |  __init__(self, x=0, y=0, text='', color=None, verticalalignment='baseline', horizontalalignment='left', multialignment=None, fontproperties=None, rotation=None, linespacing=None, rotation_mode=None, usetex=None, wrap=False, **kwargs)
 |      Create a `.Text` instance at *x*, *y* with string *text*.
 |
 |      Valid keyword arguments are:
 |
 |      Properties:
 |          agg_filter: a filter function, which takes a (m, n, 3) float array and a dpi value, and returns a (m, n, 3) array
 |          alpha: float or None
 |          animated: bool
 |          backgroundcolor: color
 |          bbox: dict with properties for `.patches.FancyBboxPatch`
 |          clip_box: `.Bbox`
 |          clip_on: bool
 |          clip_path: Patch or (Path, Transform) or None
 |          color or c: color
 |          contains: unknown
 |          figure: `.Figure`
 |          fontfamily or family: {FONTNAME, 'serif', 'sans-serif', 'cursive', 'fantasy', 'monospace'}
 |          fontproperties or font or font_properties: `.font_manager.FontProperties` or `str` or `pathlib.Path`
 |          fontsize or size: float or {'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'}
 |          fontstretch or stretch: {a numeric value in range 0-1000, 'ultra-condensed', 'extra-condensed', 'condensed', 'semi-condensed', 'normal', 'semi-expanded', 'expanded', 'extra-expanded', 'ultra-expanded'}
 |          fontstyle or style: {'normal', 'italic', 'oblique'}
 |          fontvariant or variant: {'normal', 'small-caps'}
 |          fontweight or weight: {a numeric value in range 0-1000, 'ultralight', 'light', 'normal', 'regular', 'book', 'medium', 'roman', 'semibold', 'demibold', 'demi', 'bold', 'heavy', 'extra bold', 'black'}
 |          gid: str
 |          horizontalalignment or ha: {'center', 'right', 'left'}
 |          in_layout: bool
 |          label: object
 |          linespacing: float (multiple of font size)
 |          multialignment or ma: {'left', 'right', 'center'}
 |          path_effects: `.AbstractPathEffect`
 |          picker: None or bool or callable
 |          position: (float, float)
 |          rasterized: bool or None
 |          rotation: float or {'vertical', 'horizontal'}
 |          rotation_mode: {None, 'default', 'anchor'}
 |          sketch_params: (scale: float, length: float, randomness: float)
 |          snap: bool or None
 |          text: object
 |          transform: `.Transform`
 |          url: str
 |          usetex: bool or None
 |          verticalalignment or va: {'center', 'top', 'bottom', 'baseline', 'center_baseline'}
 |          visible: bool
 |          wrap: bool
 |          x: float
 |          y: float
 |          zorder: float
 |
 |  __repr__(self)
 |      Return repr(self).
 |
 |  contains(self, mouseevent)
 |      Return whether the mouse event occurred inside the axis-aligned
 |      bounding-box of the text.
 |
 |  draw(self, renderer)
 |      Draw the Artist (and its children) using the given renderer.
 |
 |      This has no effect if the artist is not visible (`.Artist.get_visible`
 |      returns False).
 |
 |      Parameters
 |      ----------
 |      renderer : `.RendererBase` subclass.
 |
 |      Notes
 |      -----
 |      This method is overridden in the Artist subclasses.
 |
 |  get_bbox_patch(self)
 |      Return the bbox Patch, or None if the `.patches.FancyBboxPatch`
 |      is not made.
 |
 |  get_c(self)
 |      Alias for `get_color`.
 |
 |  get_color(self)
 |      Return the color of the text.
 |
 |  get_family(self)
 |      Alias for `get_fontfamily`.
 |
 |  get_font(self)
 |      Alias for `get_fontproperties`.
 |
 |  get_font_properties(self)
 |      Alias for `get_fontproperties`.
 |
 |  get_fontfamily(self)
 |      Return the list of font families used for font lookup.
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.get_family
 |
 |  get_fontname(self)
 |      Return the font name as a string.
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.get_name
 |
 |  get_fontproperties(self)
 |      Return the `.font_manager.FontProperties`.
 |
 |  get_fontsize(self)
 |      Return the font size as an integer.
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.get_size_in_points
 |
 |  get_fontstyle(self)
 |      Return the font style as a string.
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.get_style
 |
 |  get_fontvariant(self)
 |      Return the font variant as a string.
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.get_variant
 |
 |  get_fontweight(self)
 |      Return the font weight as a string or a number.
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.get_weight
 |
 |  get_ha(self)
 |      Alias for `get_horizontalalignment`.
 |
 |  get_horizontalalignment(self)
 |      Return the horizontal alignment as a string.  Will be one of
 |      'left', 'center' or 'right'.
 |
 |  get_name(self)
 |      Alias for `get_fontname`.
 |
 |  get_position(self)
 |      Return the (x, y) position of the text.
 |
 |  get_prop_tup(self, renderer=None)
 |      Return a hashable tuple of properties.
 |
 |      Not intended to be human readable, but useful for backends who
 |      want to cache derived information about text (e.g., layouts) and
 |      need to know if the text has changed.
 |
 |  get_rotation(self)
 |      Return the text angle in degrees between 0 and 360.
 |
 |  get_rotation_mode(self)
 |      Return the text rotation mode.
 |
 |  get_size(self)
 |      Alias for `get_fontsize`.
 |
 |  get_stretch(self)
 |      Return the font stretch as a string or a number.
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.get_stretch
 |
 |  get_style(self)
 |      Alias for `get_fontstyle`.
 |
 |  get_text(self)
 |      Return the text string.
 |
 |  get_unitless_position(self)
 |      Return the (x, y) unitless position of the text.
 |
 |  get_usetex(self)
 |      Return whether this `Text` object uses TeX for rendering.
 |
 |  get_va(self)
 |      Alias for `get_verticalalignment`.
 |
 |  get_variant(self)
 |      Alias for `get_fontvariant`.
 |
 |  get_verticalalignment(self)
 |      Return the vertical alignment as a string.  Will be one of
 |      'top', 'center', 'bottom' or 'baseline'.
 |
 |  get_weight(self)
 |      Alias for `get_fontweight`.
 |
 |  get_window_extent(self, renderer=None, dpi=None)
 |      Return the `.Bbox` bounding the text, in display units.
 |
 |      In addition to being used internally, this is useful for specifying
 |      clickable regions in a png file on a web page.
 |
 |      Parameters
 |      ----------
 |      renderer : Renderer, optional
 |          A renderer is needed to compute the bounding box.  If the artist
 |          has already been drawn, the renderer is cached; thus, it is only
 |          necessary to pass this argument when calling `get_window_extent`
 |          before the first `draw`.  In practice, it is usually easier to
 |          trigger a draw first (e.g. by saving the figure).
 |
 |      dpi : float, optional
 |          The dpi value for computing the bbox, defaults to
 |          ``self.figure.dpi`` (*not* the renderer dpi); should be set e.g. if
 |          to match regions with a figure saved with a custom dpi value.
 |
 |  get_wrap(self)
 |      Return whether the text can be wrapped.
 |
 |  set_backgroundcolor(self, color)
 |      Set the background color of the text by updating the bbox.
 |
 |      Parameters
 |      ----------
 |      color : color
 |
 |      See Also
 |      --------
 |      .set_bbox : To change the position of the bounding box
 |
 |  set_bbox(self, rectprops)
 |      Draw a bounding box around self.
 |
 |      Parameters
 |      ----------
 |      rectprops : dict with properties for `.patches.FancyBboxPatch`
 |           The default boxstyle is 'square'. The mutation
 |           scale of the `.patches.FancyBboxPatch` is set to the fontsize.
 |
 |      Examples
 |      --------
 |      ::
 |
 |          t.set_bbox(dict(facecolor='red', alpha=0.5))
 |
 |  set_c(self, color)
 |      Alias for `set_color`.
 |
 |  set_clip_box(self, clipbox)
 |      Set the artist's clip `.Bbox`.
 |
 |      Parameters
 |      ----------
 |      clipbox : `.Bbox`
 |
 |  set_clip_on(self, b)
 |      Set whether the artist uses clipping.
 |
 |      When False artists will be visible outside of the axes which
 |      can lead to unexpected results.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_clip_path(self, path, transform=None)
 |      Set the artist's clip path.
 |
 |      Parameters
 |      ----------
 |      path : `.Patch` or `.Path` or `.TransformedPath` or None
 |          The clip path. If given a `.Path`, *transform* must be provided as
 |          well. If *None*, a previously set clip path is removed.
 |      transform : `~matplotlib.transforms.Transform`, optional
 |          Only used if *path* is a `.Path`, in which case the given `.Path`
 |          is converted to a `.TransformedPath` using *transform*.
 |
 |      Notes
 |      -----
 |      For efficiency, if *path* is a `.Rectangle` this method will set the
 |      clipping box to the corresponding rectangle and set the clipping path
 |      to ``None``.
 |
 |      For technical reasons (support of `~.Artist.set`), a tuple
 |      (*path*, *transform*) is also accepted as a single positional
 |      parameter.
 |
 |      .. ACCEPTS: Patch or (Path, Transform) or None
 |
 |  set_color(self, color)
 |      Set the foreground color of the text
 |
 |      Parameters
 |      ----------
 |      color : color
 |
 |  set_family(self, fontname)
 |      Alias for `set_fontfamily`.
 |
 |  set_font(self, fp)
 |      Alias for `set_fontproperties`.
 |
 |  set_font_properties(self, fp)
 |      Alias for `set_fontproperties`.
 |
 |  set_fontfamily(self, fontname)
 |      Set the font family.  May be either a single string, or a list of
 |      strings in decreasing priority.  Each string may be either a real font
 |      name or a generic font class name.  If the latter, the specific font
 |      names will be looked up in the corresponding rcParams.
 |
 |      If a `Text` instance is constructed with ``fontfamily=None``, then the
 |      font is set to :rc:`font.family`, and the
 |      same is done when `set_fontfamily()` is called on an existing
 |      `Text` instance.
 |
 |      Parameters
 |      ----------
 |      fontname : {FONTNAME, 'serif', 'sans-serif', 'cursive', 'fantasy', 'monospace'}
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.set_family
 |
 |  set_fontname(self, fontname)
 |      Alias for `set_family`.
 |
 |      One-way alias only: the getter differs.
 |
 |      Parameters
 |      ----------
 |      fontname : {FONTNAME, 'serif', 'sans-serif', 'cursive', 'fantasy', 'monospace'}
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.set_family
 |
 |  set_fontproperties(self, fp)
 |      Set the font properties that control the text.
 |
 |      Parameters
 |      ----------
 |      fp : `.font_manager.FontProperties` or `str` or `pathlib.Path`
 |          If a `str`, it is interpreted as a fontconfig pattern parsed by
 |          `.FontProperties`.  If a `pathlib.Path`, it is interpreted as the
 |          absolute path to a font file.
 |
 |  set_fontsize(self, fontsize)
 |      Set the font size.
 |
 |      Parameters
 |      ----------
 |      fontsize : float or {'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'}
 |          If float, the fontsize in points. The string values denote sizes
 |          relative to the default font size.
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.set_size
 |
 |  set_fontstretch(self, stretch)
 |      Set the font stretch (horizontal condensation or expansion).
 |
 |      Parameters
 |      ----------
 |      stretch : {a numeric value in range 0-1000, 'ultra-condensed', 'extra-condensed', 'condensed', 'semi-condensed', 'normal', 'semi-expanded', 'expanded', 'extra-expanded', 'ultra-expanded'}
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.set_stretch
 |
 |  set_fontstyle(self, fontstyle)
 |      Set the font style.
 |
 |      Parameters
 |      ----------
 |      fontstyle : {'normal', 'italic', 'oblique'}
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.set_style
 |
 |  set_fontvariant(self, variant)
 |      Set the font variant.
 |
 |      Parameters
 |      ----------
 |      variant : {'normal', 'small-caps'}
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.set_variant
 |
 |  set_fontweight(self, weight)
 |      Set the font weight.
 |
 |      Parameters
 |      ----------
 |      weight : {a numeric value in range 0-1000, 'ultralight', 'light', 'normal', 'regular', 'book', 'medium', 'roman', 'semibold', 'demibold', 'demi', 'bold', 'heavy', 'extra bold', 'black'}
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.set_weight
 |
 |  set_ha(self, align)
 |      Alias for `set_horizontalalignment`.
 |
 |  set_horizontalalignment(self, align)
 |      Set the horizontal alignment to one of
 |
 |      Parameters
 |      ----------
 |      align : {'center', 'right', 'left'}
 |
 |  set_linespacing(self, spacing)
 |      Set the line spacing as a multiple of the font size.
 |
 |      The default line spacing is 1.2.
 |
 |      Parameters
 |      ----------
 |      spacing : float (multiple of font size)
 |
 |  set_ma(self, align)
 |      Alias for `set_multialignment`.
 |
 |  set_multialignment(self, align)
 |      Set the text alignment for multiline texts.
 |
 |      The layout of the bounding box of all the lines is determined by the
 |      horizontalalignment and verticalalignment properties. This property
 |      controls the alignment of the text lines within that box.
 |
 |      Parameters
 |      ----------
 |      align : {'left', 'right', 'center'}
 |
 |  set_name(self, fontname)
 |      Alias for `set_fontname`.
 |
 |  set_position(self, xy)
 |      Set the (*x*, *y*) position of the text.
 |
 |      Parameters
 |      ----------
 |      xy : (float, float)
 |
 |  set_rotation(self, s)
 |      Set the rotation of the text.
 |
 |      Parameters
 |      ----------
 |      s : float or {'vertical', 'horizontal'}
 |          The rotation angle in degrees in mathematically positive direction
 |          (counterclockwise). 'horizontal' equals 0, 'vertical' equals 90.
 |
 |  set_rotation_mode(self, m)
 |      Set text rotation mode.
 |
 |      Parameters
 |      ----------
 |      m : {None, 'default', 'anchor'}
 |          If ``None`` or ``"default"``, the text will be first rotated, then
 |          aligned according to their horizontal and vertical alignments.  If
 |          ``"anchor"``, then alignment occurs before rotation.
 |
 |  set_size(self, fontsize)
 |      Alias for `set_fontsize`.
 |
 |  set_stretch(self, stretch)
 |      Alias for `set_fontstretch`.
 |
 |  set_style(self, fontstyle)
 |      Alias for `set_fontstyle`.
 |
 |  set_text(self, s)
 |      Set the text string *s*.
 |
 |      It may contain newlines (``\n``) or math in LaTeX syntax.
 |
 |      Parameters
 |      ----------
 |      s : object
 |          Any object gets converted to its `str` representation, except for
 |          ``None`` which is converted to an empty string.
 |
 |  set_usetex(self, usetex)
 |      Parameters
 |      ----------
 |      usetex : bool or None
 |          Whether to render using TeX, ``None`` means to use
 |          :rc:`text.usetex`.
 |
 |  set_va(self, align)
 |      Alias for `set_verticalalignment`.
 |
 |  set_variant(self, variant)
 |      Alias for `set_fontvariant`.
 |
 |  set_verticalalignment(self, align)
 |      Set the vertical alignment.
 |
 |      Parameters
 |      ----------
 |      align : {'center', 'top', 'bottom', 'baseline', 'center_baseline'}
 |
 |  set_weight(self, weight)
 |      Alias for `set_fontweight`.
 |
 |  set_wrap(self, wrap)
 |      Set whether the text can be wrapped.
 |
 |      Parameters
 |      ----------
 |      wrap : bool
 |
 |  set_x(self, x)
 |      Set the *x* position of the text.
 |
 |      Parameters
 |      ----------
 |      x : float
 |
 |  set_y(self, y)
 |      Set the *y* position of the text.
 |
 |      Parameters
 |      ----------
 |      y : float
 |
 |  update(self, kwargs)
 |      Update this artist's properties from the dict *props*.
 |
 |      Parameters
 |      ----------
 |      props : dict
 |
 |  update_bbox_position_size(self, renderer)
 |      Update the location and the size of the bbox.
 |
 |      This method should be used when the position and size of the bbox needs
 |      to be updated before actually drawing the bbox.
 |
 |  update_from(self, other)
 |      Copy properties from *other* to *self*.
 |
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |
 |  zorder = 3
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from matplotlib.artist.Artist:
 |
 |  add_callback(self, func)
 |      Add a callback function that will be called whenever one of the
 |      `.Artist`'s properties changes.
 |
 |      Parameters
 |      ----------
 |      func : callable
 |          The callback function. It must have the signature::
 |
 |              def func(artist: Artist) -> Any
 |
 |          where *artist* is the calling `.Artist`. Return values may exist
 |          but are ignored.
 |
 |      Returns
 |      -------
 |      int
 |          The observer id associated with the callback. This id can be
 |          used for removing the callback with `.remove_callback` later.
 |
 |      See Also
 |      --------
 |      remove_callback
 |
 |  convert_xunits(self, x)
 |      Convert *x* using the unit type of the xaxis.
 |
 |      If the artist is not in contained in an Axes or if the xaxis does not
 |      have units, *x* itself is returned.
 |
 |  convert_yunits(self, y)
 |      Convert *y* using the unit type of the yaxis.
 |
 |      If the artist is not in contained in an Axes or if the yaxis does not
 |      have units, *y* itself is returned.
 |
 |  findobj(self, match=None, include_self=True)
 |      Find artist objects.
 |
 |      Recursively find all `.Artist` instances contained in the artist.
 |
 |      Parameters
 |      ----------
 |      match
 |          A filter criterion for the matches. This can be
 |
 |          - *None*: Return all objects contained in artist.
 |          - A function with signature ``def match(artist: Artist) -> bool``.
 |            The result will only contain artists for which the function
 |            returns *True*.
 |          - A class instance: e.g., `.Line2D`. The result will only contain
 |            artists of this class or its subclasses (``isinstance`` check).
 |
 |      include_self : bool
 |          Include *self* in the list to be checked for a match.
 |
 |      Returns
 |      -------
 |      list of `.Artist`
 |
 |  format_cursor_data(self, data)
 |      Return a string representation of *data*.
 |
 |      .. note::
 |          This method is intended to be overridden by artist subclasses.
 |          As an end-user of Matplotlib you will most likely not call this
 |          method yourself.
 |
 |      The default implementation converts ints and floats and arrays of ints
 |      and floats into a comma-separated string enclosed in square brackets.
 |
 |      See Also
 |      --------
 |      get_cursor_data
 |
 |  get_agg_filter(self)
 |      Return filter function to be used for agg filter.
 |
 |  get_alpha(self)
 |      Return the alpha value used for blending - not supported on all
 |      backends.
 |
 |  get_animated(self)
 |      Return whether the artist is animated.
 |
 |  get_children(self)
 |      Return a list of the child `.Artist`\s of this `.Artist`.
 |
 |  get_clip_box(self)
 |      Return the clipbox.
 |
 |  get_clip_on(self)
 |      Return whether the artist uses clipping.
 |
 |  get_clip_path(self)
 |      Return the clip path.
 |
 |  get_contains(self)
 |      [*Deprecated*] Return the custom contains function of the artist if set, or *None*.
 |
 |      See Also
 |      --------
 |      set_contains
 |
 |      Notes
 |      -----
 |      .. deprecated:: 3.3
 |
 |  get_cursor_data(self, event)
 |      Return the cursor data for a given event.
 |
 |      .. note::
 |          This method is intended to be overridden by artist subclasses.
 |          As an end-user of Matplotlib you will most likely not call this
 |          method yourself.
 |
 |      Cursor data can be used by Artists to provide additional context
 |      information for a given event. The default implementation just returns
 |      *None*.
 |
 |      Subclasses can override the method and return arbitrary data. However,
 |      when doing so, they must ensure that `.format_cursor_data` can convert
 |      the data to a string representation.
 |
 |      The only current use case is displaying the z-value of an `.AxesImage`
 |      in the status bar of a plot window, while moving the mouse.
 |
 |      Parameters
 |      ----------
 |      event : `matplotlib.backend_bases.MouseEvent`
 |
 |      See Also
 |      --------
 |      format_cursor_data
 |
 |  get_figure(self)
 |      Return the `.Figure` instance the artist belongs to.
 |
 |  get_gid(self)
 |      Return the group id.
 |
 |  get_in_layout(self)
 |      Return boolean flag, ``True`` if artist is included in layout
 |      calculations.
 |
 |      E.g. :doc:`/tutorials/intermediate/constrainedlayout_guide`,
 |      `.Figure.tight_layout()`, and
 |      ``fig.savefig(fname, bbox_inches='tight')``.
 |
 |  get_label(self)
 |      Return the label used for this artist in the legend.
 |
 |  get_path_effects(self)
 |
 |  get_picker(self)
 |      Return the picking behavior of the artist.
 |
 |      The possible values are described in `.set_picker`.
 |
 |      See Also
 |      --------
 |      set_picker, pickable, pick
 |
 |  get_rasterized(self)
 |      Return whether the artist is to be rasterized.
 |
 |  get_sketch_params(self)
 |      Return the sketch parameters for the artist.
 |
 |      Returns
 |      -------
 |      tuple or None
 |
 |          A 3-tuple with the following elements:
 |
 |          - *scale*: The amplitude of the wiggle perpendicular to the
 |            source line.
 |          - *length*: The length of the wiggle along the line.
 |          - *randomness*: The scale factor by which the length is
 |            shrunken or expanded.
 |
 |          Returns *None* if no sketch parameters were set.
 |
 |  get_snap(self)
 |      Return the snap setting.
 |
 |      See `.set_snap` for details.
 |
 |  get_tightbbox(self, renderer)
 |      Like `.Artist.get_window_extent`, but includes any clipping.
 |
 |      Parameters
 |      ----------
 |      renderer : `.RendererBase` subclass
 |          renderer that will be used to draw the figures (i.e.
 |          ``fig.canvas.get_renderer()``)
 |
 |      Returns
 |      -------
 |      `.Bbox`
 |          The enclosing bounding box (in figure pixel coordinates).
 |
 |  get_transform(self)
 |      Return the `.Transform` instance used by this artist.
 |
 |  get_transformed_clip_path_and_affine(self)
 |      Return the clip path with the non-affine part of its
 |      transformation applied, and the remaining affine part of its
 |      transformation.
 |
 |  get_url(self)
 |      Return the url.
 |
 |  get_visible(self)
 |      Return the visibility.
 |
 |  get_zorder(self)
 |      Return the artist's zorder.
 |
 |  have_units(self)
 |      Return *True* if units are set on any axis.
 |
 |  is_transform_set(self)
 |      Return whether the Artist has an explicitly set transform.
 |
 |      This is *True* after `.set_transform` has been called.
 |
 |  pchanged(self)
 |      Call all of the registered callbacks.
 |
 |      This function is triggered internally when a property is changed.
 |
 |      See Also
 |      --------
 |      add_callback
 |      remove_callback
 |
 |  pick(self, mouseevent)
 |      Process a pick event.
 |
 |      Each child artist will fire a pick event if *mouseevent* is over
 |      the artist and the artist has picker set.
 |
 |      See Also
 |      --------
 |      set_picker, get_picker, pickable
 |
 |  pickable(self)
 |      Return whether the artist is pickable.
 |
 |      See Also
 |      --------
 |      set_picker, get_picker, pick
 |
 |  properties(self)
 |      Return a dictionary of all the properties of the artist.
 |
 |  remove(self)
 |      Remove the artist from the figure if possible.
 |
 |      The effect will not be visible until the figure is redrawn, e.g.,
 |      with `.FigureCanvasBase.draw_idle`.  Call `~.axes.Axes.relim` to
 |      update the axes limits if desired.
 |
 |      Note: `~.axes.Axes.relim` will not see collections even if the
 |      collection was added to the axes with *autolim* = True.
 |
 |      Note: there is no support for removing the artist's legend entry.
 |
 |  remove_callback(self, oid)
 |      Remove a callback based on its observer id.
 |
 |      See Also
 |      --------
 |      add_callback
 |
 |  set(self, **kwargs)
 |      A property batch setter.  Pass *kwargs* to set properties.
 |
 |  set_agg_filter(self, filter_func)
 |      Set the agg filter.
 |
 |      Parameters
 |      ----------
 |      filter_func : callable
 |          A filter function, which takes a (m, n, 3) float array and a dpi
 |          value, and returns a (m, n, 3) array.
 |
 |          .. ACCEPTS: a filter function, which takes a (m, n, 3) float array
 |              and a dpi value, and returns a (m, n, 3) array
 |
 |  set_alpha(self, alpha)
 |      Set the alpha value used for blending - not supported on all backends.
 |
 |      Parameters
 |      ----------
 |      alpha : float or None
 |
 |  set_animated(self, b)
 |      Set the artist's animation state.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_contains(self, picker)
 |      [*Deprecated*] Define a custom contains syntax for the artist.
 |
 |      The provided callable replaces the default `.contains` method
 |      of the artist.
 |
 |      Parameters
 |      ----------
 |      picker : callable
 |          A custom picker function to evaluate if an event is within the
 |          artist. The function must have the signature::
 |
 |              def contains(artist: Artist, event: MouseEvent) -> bool, dict
 |
 |          that returns:
 |
 |          - a bool indicating if the event is within the artist
 |          - a dict of additional information. The dict should at least
 |            return the same information as the default ``contains()``
 |            implementation of the respective artist, but may provide
 |            additional information.
 |
 |      Notes
 |      -----
 |      .. deprecated:: 3.3
 |
 |  set_figure(self, fig)
 |      Set the `.Figure` instance the artist belongs to.
 |
 |      Parameters
 |      ----------
 |      fig : `.Figure`
 |
 |  set_gid(self, gid)
 |      Set the (group) id for the artist.
 |
 |      Parameters
 |      ----------
 |      gid : str
 |
 |  set_in_layout(self, in_layout)
 |      Set if artist is to be included in layout calculations,
 |      E.g. :doc:`/tutorials/intermediate/constrainedlayout_guide`,
 |      `.Figure.tight_layout()`, and
 |      ``fig.savefig(fname, bbox_inches='tight')``.
 |
 |      Parameters
 |      ----------
 |      in_layout : bool
 |
 |  set_label(self, s)
 |      Set a label that will be displayed in the legend.
 |
 |      Parameters
 |      ----------
 |      s : object
 |          *s* will be converted to a string by calling `str`.
 |
 |  set_path_effects(self, path_effects)
 |      Set the path effects.
 |
 |      Parameters
 |      ----------
 |      path_effects : `.AbstractPathEffect`
 |
 |  set_picker(self, picker)
 |      Define the picking behavior of the artist.
 |
 |      Parameters
 |      ----------
 |      picker : None or bool or callable
 |          This can be one of the following:
 |
 |          - *None*: Picking is disabled for this artist (default).
 |
 |          - A boolean: If *True* then picking will be enabled and the
 |            artist will fire a pick event if the mouse event is over
 |            the artist.
 |
 |          - A function: If picker is callable, it is a user supplied
 |            function which determines whether the artist is hit by the
 |            mouse event::
 |
 |              hit, props = picker(artist, mouseevent)
 |
 |            to determine the hit syntax.  if the mouse event is over the
 |            artist, return *hit=True* and props is a dictionary of
 |            properties you want added to the PickEvent attributes.
 |
 |          - *deprecated*: For `.Line2D` only, *picker* can also be a float
 |            that sets the tolerance for checking whether an event occurred
 |            "on" the line; this is deprecated.  Use `.Line2D.set_pickradius`
 |            instead.
 |
 |  set_rasterized(self, rasterized)
 |      Force rasterized (bitmap) drawing in vector backend output.
 |
 |      Defaults to None, which implies the backend's default behavior.
 |
 |      Parameters
 |      ----------
 |      rasterized : bool or None
 |
 |  set_sketch_params(self, scale=None, length=None, randomness=None)
 |      Sets the sketch parameters.
 |
 |      Parameters
 |      ----------
 |      scale : float, optional
 |          The amplitude of the wiggle perpendicular to the source
 |          line, in pixels.  If scale is `None`, or not provided, no
 |          sketch filter will be provided.
 |      length : float, optional
 |           The length of the wiggle along the line, in pixels
 |           (default 128.0)
 |      randomness : float, optional
 |          The scale factor by which the length is shrunken or
 |          expanded (default 16.0)
 |
 |          .. ACCEPTS: (scale: float, length: float, randomness: float)
 |
 |  set_snap(self, snap)
 |      Set the snapping behavior.
 |
 |      Snapping aligns positions with the pixel grid, which results in
 |      clearer images. For example, if a black line of 1px width was
 |      defined at a position in between two pixels, the resulting image
 |      would contain the interpolated value of that line in the pixel grid,
 |      which would be a grey value on both adjacent pixel positions. In
 |      contrast, snapping will move the line to the nearest integer pixel
 |      value, so that the resulting image will really contain a 1px wide
 |      black line.
 |
 |      Snapping is currently only supported by the Agg and MacOSX backends.
 |
 |      Parameters
 |      ----------
 |      snap : bool or None
 |          Possible values:
 |
 |          - *True*: Snap vertices to the nearest pixel center.
 |          - *False*: Do not modify vertex positions.
 |          - *None*: (auto) If the path contains only rectilinear line
 |            segments, round to the nearest pixel center.
 |
 |  set_transform(self, t)
 |      Set the artist transform.
 |
 |      Parameters
 |      ----------
 |      t : `.Transform`
 |
 |  set_url(self, url)
 |      Set the url for the artist.
 |
 |      Parameters
 |      ----------
 |      url : str
 |
 |  set_visible(self, b)
 |      Set the artist's visibility.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_zorder(self, level)
 |      Set the zorder for the artist.  Artists with lower zorder
 |      values are drawn first.
 |
 |      Parameters
 |      ----------
 |      level : float
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from matplotlib.artist.Artist:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)
 |
 |  axes
 |      The `~.axes.Axes` instance the artist resides in, or *None*.
 |
 |  mouseover
 |      If this property is set to *True*, the artist will be queried for
 |      custom context information when the mouse cursor moves over it.
 |
 |      See also :meth:`get_cursor_data`, :class:`.ToolCursorPosition` and
 |      :class:`.NavigationToolbar2`.
 |
 |  stale
 |      Whether the artist is 'stale' and needs to be re-drawn for the output
 |      to match the internal state of the artist.
 |
 |  sticky_edges
 |      ``x`` and ``y`` sticky edge lists for autoscaling.
 |
 |      When performing autoscaling, if a data limit coincides with a value in
 |      the corresponding sticky_edges list, then no margin will be added--the
 |      view limit "sticks" to the edge. A typical use case is histograms,
 |      where one usually expects no margin on the bottom edge (0) of the
 |      histogram.
 |
 |      This attribute cannot be assigned to; however, the ``x`` and ``y``
 |      lists can be modified in place as needed.
 |
 |      Examples
 |      --------
 |      >>> artist.sticky_edges.x[:] = (xmin, xmax)
 |      >>> artist.sticky_edges.y[:] = (ymin, ymax)
    """

    @staticmethod
    def text():
        fig, ax = plt.subplots()
        x = np.arange(0, 2*np.pi, 0.1)
        y = np.sin(x)
        z = 1 - np.cos(x)
        ax.plot(x, y)
        ax.plot(x, z)

        pointsx = (np.pi/10, np.pi/3*2, np.pi, np.pi/4*7)
        pointsy = tuple(np.sin(_x) for _x in pointsx)
        text1 = r'$sin(\frac{\pi}{10})=$' + '{:1.3f}'.format(np.sin(pointsx[0]))
        ax.text(pointsx[0]+0.1, pointsy[0],
                s=text1
                )
        text2 = r'$sin(\frac{3\pi}{2})=$' + '{:1.3f}'.format(np.sin(pointsx[1]))
        ax.text(pointsx[1]+0.1, pointsy[1],
                s=text2,
                fontsize=16,
                fontstyle='oblique',
                rotation=10,
                bbox=dict(facecolor='red', alpha=0.3, boxstyle='sawtooth')
                )
        text3 = r'$sin({\pi})=$' + '{:1.3f}'.format(np.sin(pointsx[2]))
        ax.text(pointsx[2]+0.1, pointsy[2],
                s=text3,
                color='r',
                rotation='vertical',
                bbox=dict(facecolor='red', alpha=0.3),
                )
        # text4 = r'$sin(\frac{7\pi}{4})=$' + '{:1.10f}'.format(np.sin(pointsx[3]))
        text4 = r'this is a long text display exmaple, x=$sin(\frac{7\pi}{4})$,' + \
                ' y={:.2f}'.format(np.sin(pointsx[3]))
        ax.text(pointsx[3]+0.1, pointsy[3],
                s=text4,
                ha='left',
                va='bottom',
                wrap=True       # 仅当文本串中出现空格时，根据显示空间进行换行
                )
        text5 = r"$\int_0^x{sin(t)}\mathrm{dt}$"
        ax.text(np.pi+0.1, 1-np.cos(np.pi),
                s=text5
                )

        ax.set_ylim(-1.01, 2.1)
        ax.set_xlim(0, 2*np.pi-0.1)
        ax.spines['top'].set_color('none')
        ax.spines['right'].set_color('none')
        ax.scatter(x=pointsx, y=pointsy, s=50, c='r')
        ax.scatter(x=np.pi, y=1-np.cos(np.pi), s=50, c='r')


class DemoAnnotation:

    """
class Annotation(Text, _AnnotationBase)
 |  Annotation(text, xy, xytext=None, xycoords='data', textcoords=None, arrowprops=None,
               annotation_clip=None, **kwargs)
 |
 |  An `.Annotation` is a `.Text` that can refer to a specific position *xy*.
 |  Optionally an arrow pointing from the text to *xy* can be drawn.
 |
 |  Attributes
 |  ----------
 |  xy
 |      The annotated position.
 |  xycoords
 |      The coordinate system for *xy*.
 |  arrow_patch
 |      A `.FancyArrowPatch` to point from *xytext* to *xy*.
 |
 |  Method resolution order:
 |      Annotation
 |      Text
 |      matplotlib.artist.Artist
 |      _AnnotationBase
 |      builtins.object
 |
 |  Methods defined here:
 |
 |  __init__(self, text, xy, xytext=None, xycoords='data', textcoords=None, arrowprops=None, annotation_clip=None, **kwargs)
 |      Annotate the point *xy* with text *text*.
 |
 |      In the simplest form, the text is placed at *xy*.
 |
 |      Optionally, the text can be displayed in another position *xytext*.
 |      An arrow pointing from the text to the annotated point *xy* can then
 |      be added by defining *arrowprops*.
 |
 |      Parameters
 |      ----------
 |      text : str
 |          The text of the annotation.  *s* is a deprecated synonym for this
 |          parameter.
 |
 |      xy : (float, float)
 |          The point *(x, y)* to annotate. The coordinate system is determined
 |          by *xycoords*.
 |
 |      xytext : (float, float), default: *xy*
 |          The position *(x, y)* to place the text at. The coordinate system
 |          is determined by *textcoords*.
 |
 |      xycoords : str or `.Artist` or `.Transform` or callable or (float, float), default: 'data'
 |
 |          The coordinate system that *xy* is given in. The following types
 |          of values are supported:
 |
 |          - One of the following strings:
 |
 |            =================   =============================================
 |            Value               Description
 |            =================   =============================================
 |            'figure points'     Points from the lower left of the figure
 |            'figure pixels'     Pixels from the lower left of the figure
 |            'figure fraction'   Fraction of figure from lower left
 |            'axes points'       Points from lower left corner of axes
 |            'axes pixels'       Pixels from lower left corner of axes
 |            'axes fraction'     Fraction of axes from lower left
 |            'data'              Use the coordinate system of the object being
 |                                annotated (default)
 |            'polar'             *(theta, r)* if not native 'data' coordinates
 |            =================   =============================================
 |
 |          - An `.Artist`: *xy* is interpreted as a fraction of the artist's
 |            `~matplotlib.transforms.Bbox`. E.g. *(0, 0)* would be the lower
 |            left corner of the bounding box and *(0.5, 1)* would be the
 |            center top of the bounding box.
 |
 |          - A `.Transform` to transform *xy* to screen coordinates.
 |
 |          - A function with one of the following signatures::
 |
 |              def transform(renderer) -> Bbox
 |              def transform(renderer) -> Transform
 |
 |            where *renderer* is a `.RendererBase` subclass.
 |
 |            The result of the function is interpreted like the `.Artist` and
 |            `.Transform` cases above.
 |
 |          - A tuple *(xcoords, ycoords)* specifying separate coordinate
 |            systems for *x* and *y*. *xcoords* and *ycoords* must each be
 |            of one of the above described types.
 |
 |          See :obj:`plotting-guide-annotation` for more details.
 |
 |      textcoords : str or `.Artist` or `.Transform` or callable or (float, float), default: value of *xycoords*
 |          The coordinate system that *xytext* is given in.
 |
 |          All *xycoords* values are valid as well as the following
 |          strings:
 |
 |          =================   =========================================
 |          Value               Description
 |          =================   =========================================
 |          'offset points'     Offset (in points) from the *xy* value
 |          'offset pixels'     Offset (in pixels) from the *xy* value
 |          =================   =========================================
 |
 |      arrowprops : dict, optional
 |          The properties used to draw a `.FancyArrowPatch` arrow between the
 |          positions *xy* and *xytext*.
 |
 |          If *arrowprops* does not contain the key 'arrowstyle' the
 |          allowed keys are:
 |
 |          ==========   ======================================================
 |          Key          Description
 |          ==========   ======================================================
 |          width        The width of the arrow in points
 |          headwidth    The width of the base of the arrow head in points
 |          headlength   The length of the arrow head in points
 |          shrink       Fraction of total length to shrink from both ends
 |          ?            Any key to :class:`matplotlib.patches.FancyArrowPatch`
 |          ==========   ======================================================
 |
 |          If *arrowprops* contains the key 'arrowstyle' the
 |          above keys are forbidden.  The allowed values of
 |          ``'arrowstyle'`` are:
 |
 |          ============   =============================================
 |          Name           Attrs
 |          ============   =============================================
 |          ``'-'``        None
 |          ``'->'``       head_length=0.4,head_width=0.2
 |          ``'-['``       widthB=1.0,lengthB=0.2,angleB=None
 |          ``'|-|'``      widthA=1.0,widthB=1.0
 |          ``'-|>'``      head_length=0.4,head_width=0.2
 |          ``'<-'``       head_length=0.4,head_width=0.2
 |          ``'<->'``      head_length=0.4,head_width=0.2
 |          ``'<|-'``      head_length=0.4,head_width=0.2
 |          ``'<|-|>'``    head_length=0.4,head_width=0.2
 |          ``'fancy'``    head_length=0.4,head_width=0.4,tail_width=0.4
 |          ``'simple'``   head_length=0.5,head_width=0.5,tail_width=0.2
 |          ``'wedge'``    tail_width=0.3,shrink_factor=0.5
 |          ============   =============================================
 |
 |          Valid keys for `~matplotlib.patches.FancyArrowPatch` are:
 |
 |          ===============  ==================================================
 |          Key              Description
 |          ===============  ==================================================
 |          arrowstyle       the arrow style
 |          connectionstyle  the connection style
 |          relpos           default is (0.5, 0.5)
 |          patchA           default is bounding box of the text
 |          patchB           default is None
 |          shrinkA          default is 2 points
 |          shrinkB          default is 2 points
 |          mutation_scale   default is text size (in points)
 |          mutation_aspect  default is 1.
 |          ?                any key for :class:`matplotlib.patches.PathPatch`
 |          ===============  ==================================================
 |
 |          Defaults to None, i.e. no arrow is drawn.
 |
 |      annotation_clip : bool or None, default: None
 |          Whether to draw the annotation when the annotation point *xy* is
 |          outside the axes area.
 |
 |          - If *True*, the annotation will only be drawn when *xy* is
 |            within the axes.
 |          - If *False*, the annotation will always be drawn.
 |          - If *None*, the annotation will only be drawn when *xy* is
 |            within the axes and *xycoords* is 'data'.
 |
 |      **kwargs
 |          Additional kwargs are passed to `~matplotlib.text.Text`.
 |
 |      Returns
 |      -------
 |      `.Annotation`
 |
 |      See Also
 |      --------
 |      :obj:`plotting-guide-annotation`
 |
 |  __str__(self)
 |      Return str(self).
 |
 |  contains(self, event)
 |      Return whether the mouse event occurred inside the axis-aligned
 |      bounding-box of the text.
 |
 |  draw(self, renderer)
 |      Draw the Artist (and its children) using the given renderer.
 |
 |      This has no effect if the artist is not visible (`.Artist.get_visible`
 |      returns False).
 |
 |      Parameters
 |      ----------
 |      renderer : `.RendererBase` subclass.
 |
 |      Notes
 |      -----
 |      This method is overridden in the Artist subclasses.
 |
 |  get_anncoords(self)
 |      Return the coordinate system to use for `.Annotation.xyann`.
 |
 |      See also *xycoords* in `.Annotation`.
 |
 |  get_window_extent(self, renderer=None)
 |      Return the `.Bbox` bounding the text and arrow, in display units.
 |
 |      Parameters
 |      ----------
 |      renderer : Renderer, optional
 |          A renderer is needed to compute the bounding box.  If the artist
 |          has already been drawn, the renderer is cached; thus, it is only
 |          necessary to pass this argument when calling `get_window_extent`
 |          before the first `draw`.  In practice, it is usually easier to
 |          trigger a draw first (e.g. by saving the figure).
 |
 |  set_anncoords(self, coords)
 |      Set the coordinate system to use for `.Annotation.xyann`.
 |
 |      See also *xycoords* in `.Annotation`.
 |
 |  set_figure(self, fig)
 |      Set the `.Figure` instance the artist belongs to.
 |
 |      Parameters
 |      ----------
 |      fig : `.Figure`
 |
 |  update_positions(self, renderer)
 |      Update the pixel positions of the annotation text and the arrow patch.
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |
 |  anncoords
 |      The coordinate system to use for `.Annotation.xyann`.
 |
 |  xyann
 |      The text position.
 |
 |      See also *xytext* in `.Annotation`.
 |
 |  xycoords
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from Text:
 |
 |  __getstate__(self)
 |
 |  __repr__(self)
 |      Return repr(self).
 |
 |  get_bbox_patch(self)
 |      Return the bbox Patch, or None if the `.patches.FancyBboxPatch`
 |      is not made.
 |
 |  get_c(self)
 |      Alias for `get_color`.
 |
 |  get_color(self)
 |      Return the color of the text.
 |
 |  get_family(self)
 |      Alias for `get_fontfamily`.
 |
 |  get_font(self)
 |      Alias for `get_fontproperties`.
 |
 |  get_font_properties(self)
 |      Alias for `get_fontproperties`.
 |
 |  get_fontfamily(self)
 |      Return the list of font families used for font lookup.
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.get_family
 |
 |  get_fontname(self)
 |      Return the font name as a string.
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.get_name
 |
 |  get_fontproperties(self)
 |      Return the `.font_manager.FontProperties`.
 |
 |  get_fontsize(self)
 |      Return the font size as an integer.
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.get_size_in_points
 |
 |  get_fontstyle(self)
 |      Return the font style as a string.
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.get_style
 |
 |  get_fontvariant(self)
 |      Return the font variant as a string.
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.get_variant
 |
 |  get_fontweight(self)
 |      Return the font weight as a string or a number.
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.get_weight
 |
 |  get_ha(self)
 |      Alias for `get_horizontalalignment`.
 |
 |  get_horizontalalignment(self)
 |      Return the horizontal alignment as a string.  Will be one of
 |      'left', 'center' or 'right'.
 |
 |  get_name(self)
 |      Alias for `get_fontname`.
 |
 |  get_position(self)
 |      Return the (x, y) position of the text.
 |
 |  get_prop_tup(self, renderer=None)
 |      Return a hashable tuple of properties.
 |
 |      Not intended to be human readable, but useful for backends who
 |      want to cache derived information about text (e.g., layouts) and
 |      need to know if the text has changed.
 |
 |  get_rotation(self)
 |      Return the text angle in degrees between 0 and 360.
 |
 |  get_rotation_mode(self)
 |      Return the text rotation mode.
 |
 |  get_size(self)
 |      Alias for `get_fontsize`.
 |
 |  get_stretch(self)
 |      Return the font stretch as a string or a number.
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.get_stretch
 |
 |  get_style(self)
 |      Alias for `get_fontstyle`.
 |
 |  get_text(self)
 |      Return the text string.
 |
 |  get_unitless_position(self)
 |      Return the (x, y) unitless position of the text.
 |
 |  get_usetex(self)
 |      Return whether this `Text` object uses TeX for rendering.
 |
 |  get_va(self)
 |      Alias for `get_verticalalignment`.
 |
 |  get_variant(self)
 |      Alias for `get_fontvariant`.
 |
 |  get_verticalalignment(self)
 |      Return the vertical alignment as a string.  Will be one of
 |      'top', 'center', 'bottom' or 'baseline'.
 |
 |  get_weight(self)
 |      Alias for `get_fontweight`.
 |
 |  get_wrap(self)
 |      Return whether the text can be wrapped.
 |
 |  set_backgroundcolor(self, color)
 |      Set the background color of the text by updating the bbox.
 |
 |      Parameters
 |      ----------
 |      color : color
 |
 |      See Also
 |      --------
 |      .set_bbox : To change the position of the bounding box
 |
 |  set_bbox(self, rectprops)
 |      Draw a bounding box around self.
 |
 |      Parameters
 |      ----------
 |      rectprops : dict with properties for `.patches.FancyBboxPatch`
 |           The default boxstyle is 'square'. The mutation
 |           scale of the `.patches.FancyBboxPatch` is set to the fontsize.
 |
 |      Examples
 |      --------
 |      ::
 |
 |          t.set_bbox(dict(facecolor='red', alpha=0.5))
 |
 |  set_c(self, color)
 |      Alias for `set_color`.
 |
 |  set_clip_box(self, clipbox)
 |      Set the artist's clip `.Bbox`.
 |
 |      Parameters
 |      ----------
 |      clipbox : `.Bbox`
 |
 |  set_clip_on(self, b)
 |      Set whether the artist uses clipping.
 |
 |      When False artists will be visible outside of the axes which
 |      can lead to unexpected results.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_clip_path(self, path, transform=None)
 |      Set the artist's clip path.
 |
 |      Parameters
 |      ----------
 |      path : `.Patch` or `.Path` or `.TransformedPath` or None
 |          The clip path. If given a `.Path`, *transform* must be provided as
 |          well. If *None*, a previously set clip path is removed.
 |      transform : `~matplotlib.transforms.Transform`, optional
 |          Only used if *path* is a `.Path`, in which case the given `.Path`
 |          is converted to a `.TransformedPath` using *transform*.
 |
 |      Notes
 |      -----
 |      For efficiency, if *path* is a `.Rectangle` this method will set the
 |      clipping box to the corresponding rectangle and set the clipping path
 |      to ``None``.
 |
 |      For technical reasons (support of `~.Artist.set`), a tuple
 |      (*path*, *transform*) is also accepted as a single positional
 |      parameter.
 |
 |      .. ACCEPTS: Patch or (Path, Transform) or None
 |
 |  set_color(self, color)
 |      Set the foreground color of the text
 |
 |      Parameters
 |      ----------
 |      color : color
 |
 |  set_family(self, fontname)
 |      Alias for `set_fontfamily`.
 |
 |  set_font(self, fp)
 |      Alias for `set_fontproperties`.
 |
 |  set_font_properties(self, fp)
 |      Alias for `set_fontproperties`.
 |
 |  set_fontfamily(self, fontname)
 |      Set the font family.  May be either a single string, or a list of
 |      strings in decreasing priority.  Each string may be either a real font
 |      name or a generic font class name.  If the latter, the specific font
 |      names will be looked up in the corresponding rcParams.
 |
 |      If a `Text` instance is constructed with ``fontfamily=None``, then the
 |      font is set to :rc:`font.family`, and the
 |      same is done when `set_fontfamily()` is called on an existing
 |      `Text` instance.
 |
 |      Parameters
 |      ----------
 |      fontname : {FONTNAME, 'serif', 'sans-serif', 'cursive', 'fantasy', 'monospace'}
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.set_family
 |
 |  set_fontname(self, fontname)
 |      Alias for `set_family`.
 |
 |      One-way alias only: the getter differs.
 |
 |      Parameters
 |      ----------
 |      fontname : {FONTNAME, 'serif', 'sans-serif', 'cursive', 'fantasy', 'monospace'}
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.set_family
 |
 |  set_fontproperties(self, fp)
 |      Set the font properties that control the text.
 |
 |      Parameters
 |      ----------
 |      fp : `.font_manager.FontProperties` or `str` or `pathlib.Path`
 |          If a `str`, it is interpreted as a fontconfig pattern parsed by
 |          `.FontProperties`.  If a `pathlib.Path`, it is interpreted as the
 |          absolute path to a font file.
 |
 |  set_fontsize(self, fontsize)
 |      Set the font size.
 |
 |      Parameters
 |      ----------
 |      fontsize : float or {'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'}
 |          If float, the fontsize in points. The string values denote sizes
 |          relative to the default font size.
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.set_size
 |
 |  set_fontstretch(self, stretch)
 |      Set the font stretch (horizontal condensation or expansion).
 |
 |      Parameters
 |      ----------
 |      stretch : {a numeric value in range 0-1000, 'ultra-condensed', 'extra-condensed', 'condensed', 'semi-condensed', 'normal', 'semi-expanded', 'expanded', 'extra-expanded', 'ultra-expanded'}
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.set_stretch
 |
 |  set_fontstyle(self, fontstyle)
 |      Set the font style.
 |
 |      Parameters
 |      ----------
 |      fontstyle : {'normal', 'italic', 'oblique'}
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.set_style
 |
 |  set_fontvariant(self, variant)
 |      Set the font variant.
 |
 |      Parameters
 |      ----------
 |      variant : {'normal', 'small-caps'}
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.set_variant
 |
 |  set_fontweight(self, weight)
 |      Set the font weight.
 |
 |      Parameters
 |      ----------
 |      weight : {a numeric value in range 0-1000, 'ultralight', 'light', 'normal', 'regular', 'book', 'medium', 'roman', 'semibold', 'demibold', 'demi', 'bold', 'heavy', 'extra bold', 'black'}
 |
 |      See Also
 |      --------
 |      .font_manager.FontProperties.set_weight
 |
 |  set_ha(self, align)
 |      Alias for `set_horizontalalignment`.
 |
 |  set_horizontalalignment(self, align)
 |      Set the horizontal alignment to one of
 |
 |      Parameters
 |      ----------
 |      align : {'center', 'right', 'left'}
 |
 |  set_linespacing(self, spacing)
 |      Set the line spacing as a multiple of the font size.
 |
 |      The default line spacing is 1.2.
 |
 |      Parameters
 |      ----------
 |      spacing : float (multiple of font size)
 |
 |  set_ma(self, align)
 |      Alias for `set_multialignment`.
 |
 |  set_multialignment(self, align)
 |      Set the text alignment for multiline texts.
 |
 |      The layout of the bounding box of all the lines is determined by the
 |      horizontalalignment and verticalalignment properties. This property
 |      controls the alignment of the text lines within that box.
 |
 |      Parameters
 |      ----------
 |      align : {'left', 'right', 'center'}
 |
 |  set_name(self, fontname)
 |      Alias for `set_fontname`.
 |
 |  set_position(self, xy)
 |      Set the (*x*, *y*) position of the text.
 |
 |      Parameters
 |      ----------
 |      xy : (float, float)
 |
 |  set_rotation(self, s)
 |      Set the rotation of the text.
 |
 |      Parameters
 |      ----------
 |      s : float or {'vertical', 'horizontal'}
 |          The rotation angle in degrees in mathematically positive direction
 |          (counterclockwise). 'horizontal' equals 0, 'vertical' equals 90.
 |
 |  set_rotation_mode(self, m)
 |      Set text rotation mode.
 |
 |      Parameters
 |      ----------
 |      m : {None, 'default', 'anchor'}
 |          If ``None`` or ``"default"``, the text will be first rotated, then
 |          aligned according to their horizontal and vertical alignments.  If
 |          ``"anchor"``, then alignment occurs before rotation.
 |
 |  set_size(self, fontsize)
 |      Alias for `set_fontsize`.
 |
 |  set_stretch(self, stretch)
 |      Alias for `set_fontstretch`.
 |
 |  set_style(self, fontstyle)
 |      Alias for `set_fontstyle`.
 |
 |  set_text(self, s)
 |      Set the text string *s*.
 |
 |      It may contain newlines (``\n``) or math in LaTeX syntax.
 |
 |      Parameters
 |      ----------
 |      s : object
 |          Any object gets converted to its `str` representation, except for
 |          ``None`` which is converted to an empty string.
 |
 |  set_usetex(self, usetex)
 |      Parameters
 |      ----------
 |      usetex : bool or None
 |          Whether to render using TeX, ``None`` means to use
 |          :rc:`text.usetex`.
 |
 |  set_va(self, align)
 |      Alias for `set_verticalalignment`.
 |
 |  set_variant(self, variant)
 |      Alias for `set_fontvariant`.
 |
 |  set_verticalalignment(self, align)
 |      Set the vertical alignment.
 |
 |      Parameters
 |      ----------
 |      align : {'center', 'top', 'bottom', 'baseline', 'center_baseline'}
 |
 |  set_weight(self, weight)
 |      Alias for `set_fontweight`.
 |
 |  set_wrap(self, wrap)
 |      Set whether the text can be wrapped.
 |
 |      Parameters
 |      ----------
 |      wrap : bool
 |
 |  set_x(self, x)
 |      Set the *x* position of the text.
 |
 |      Parameters
 |      ----------
 |      x : float
 |
 |  set_y(self, y)
 |      Set the *y* position of the text.
 |
 |      Parameters
 |      ----------
 |      y : float
 |
 |  update(self, kwargs)
 |      Update this artist's properties from the dict *props*.
 |
 |      Parameters
 |      ----------
 |      props : dict
 |
 |  update_bbox_position_size(self, renderer)
 |      Update the location and the size of the bbox.
 |
 |      This method should be used when the position and size of the bbox needs
 |      to be updated before actually drawing the bbox.
 |
 |  update_from(self, other)
 |      Copy properties from *other* to *self*.
 |
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from Text:
 |
 |  zorder = 3
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from matplotlib.artist.Artist:
 |
 |  add_callback(self, func)
 |      Add a callback function that will be called whenever one of the
 |      `.Artist`'s properties changes.
 |
 |      Parameters
 |      ----------
 |      func : callable
 |          The callback function. It must have the signature::
 |
 |              def func(artist: Artist) -> Any
 |
 |          where *artist* is the calling `.Artist`. Return values may exist
 |          but are ignored.
 |
 |      Returns
 |      -------
 |      int
 |          The observer id associated with the callback. This id can be
 |          used for removing the callback with `.remove_callback` later.
 |
 |      See Also
 |      --------
 |      remove_callback
 |
 |  convert_xunits(self, x)
 |      Convert *x* using the unit type of the xaxis.
 |
 |      If the artist is not in contained in an Axes or if the xaxis does not
 |      have units, *x* itself is returned.
 |
 |  convert_yunits(self, y)
 |      Convert *y* using the unit type of the yaxis.
 |
 |      If the artist is not in contained in an Axes or if the yaxis does not
 |      have units, *y* itself is returned.
 |
 |  findobj(self, match=None, include_self=True)
 |      Find artist objects.
 |
 |      Recursively find all `.Artist` instances contained in the artist.
 |
 |      Parameters
 |      ----------
 |      match
 |          A filter criterion for the matches. This can be
 |
 |          - *None*: Return all objects contained in artist.
 |          - A function with signature ``def match(artist: Artist) -> bool``.
 |            The result will only contain artists for which the function
 |            returns *True*.
 |          - A class instance: e.g., `.Line2D`. The result will only contain
 |            artists of this class or its subclasses (``isinstance`` check).
 |
 |      include_self : bool
 |          Include *self* in the list to be checked for a match.
 |
 |      Returns
 |      -------
 |      list of `.Artist`
 |
 |  format_cursor_data(self, data)
 |      Return a string representation of *data*.
 |
 |      .. note::
 |          This method is intended to be overridden by artist subclasses.
 |          As an end-user of Matplotlib you will most likely not call this
 |          method yourself.
 |
 |      The default implementation converts ints and floats and arrays of ints
 |      and floats into a comma-separated string enclosed in square brackets.
 |
 |      See Also
 |      --------
 |      get_cursor_data
 |
 |  get_agg_filter(self)
 |      Return filter function to be used for agg filter.
 |
 |  get_alpha(self)
 |      Return the alpha value used for blending - not supported on all
 |      backends.
 |
 |  get_animated(self)
 |      Return whether the artist is animated.
 |
 |  get_children(self)
 |      Return a list of the child `.Artist`\s of this `.Artist`.
 |
 |  get_clip_box(self)
 |      Return the clipbox.
 |
 |  get_clip_on(self)
 |      Return whether the artist uses clipping.
 |
 |  get_clip_path(self)
 |      Return the clip path.
 |
 |  get_contains(self)
 |      [*Deprecated*] Return the custom contains function of the artist if set, or *None*.
 |
 |      See Also
 |      --------
 |      set_contains
 |
 |      Notes
 |      -----
 |      .. deprecated:: 3.3
 |
 |  get_cursor_data(self, event)
 |      Return the cursor data for a given event.
 |
 |      .. note::
 |          This method is intended to be overridden by artist subclasses.
 |          As an end-user of Matplotlib you will most likely not call this
 |          method yourself.
 |
 |      Cursor data can be used by Artists to provide additional context
 |      information for a given event. The default implementation just returns
 |      *None*.
 |
 |      Subclasses can override the method and return arbitrary data. However,
 |      when doing so, they must ensure that `.format_cursor_data` can convert
 |      the data to a string representation.
 |
 |      The only current use case is displaying the z-value of an `.AxesImage`
 |      in the status bar of a plot window, while moving the mouse.
 |
 |      Parameters
 |      ----------
 |      event : `matplotlib.backend_bases.MouseEvent`
 |
 |      See Also
 |      --------
 |      format_cursor_data
 |
 |  get_figure(self)
 |      Return the `.Figure` instance the artist belongs to.
 |
 |  get_gid(self)
 |      Return the group id.
 |
 |  get_in_layout(self)
 |      Return boolean flag, ``True`` if artist is included in layout
 |      calculations.
 |
 |      E.g. :doc:`/tutorials/intermediate/constrainedlayout_guide`,
 |      `.Figure.tight_layout()`, and
 |      ``fig.savefig(fname, bbox_inches='tight')``.
 |
 |  get_label(self)
 |      Return the label used for this artist in the legend.
 |
 |  get_path_effects(self)
 |
 |  get_picker(self)
 |      Return the picking behavior of the artist.
 |
 |      The possible values are described in `.set_picker`.
 |
 |      See Also
 |      --------
 |      set_picker, pickable, pick
 |
 |  get_rasterized(self)
 |      Return whether the artist is to be rasterized.
 |
 |  get_sketch_params(self)
 |      Return the sketch parameters for the artist.
 |
 |      Returns
 |      -------
 |      tuple or None
 |
 |          A 3-tuple with the following elements:
 |
 |          - *scale*: The amplitude of the wiggle perpendicular to the
 |            source line.
 |          - *length*: The length of the wiggle along the line.
 |          - *randomness*: The scale factor by which the length is
 |            shrunken or expanded.
 |
 |          Returns *None* if no sketch parameters were set.
 |
 |  get_snap(self)
 |      Return the snap setting.
 |
 |      See `.set_snap` for details.
 |
 |  get_tightbbox(self, renderer)
 |      Like `.Artist.get_window_extent`, but includes any clipping.
 |
 |      Parameters
 |      ----------
 |      renderer : `.RendererBase` subclass
 |          renderer that will be used to draw the figures (i.e.
 |          ``fig.canvas.get_renderer()``)
 |
 |      Returns
 |      -------
 |      `.Bbox`
 |          The enclosing bounding box (in figure pixel coordinates).
 |
 |  get_transform(self)
 |      Return the `.Transform` instance used by this artist.
 |
 |  get_transformed_clip_path_and_affine(self)
 |      Return the clip path with the non-affine part of its
 |      transformation applied, and the remaining affine part of its
 |      transformation.
 |
 |  get_url(self)
 |      Return the url.
 |
 |  get_visible(self)
 |      Return the visibility.
 |
 |  get_zorder(self)
 |      Return the artist's zorder.
 |
 |  have_units(self)
 |      Return *True* if units are set on any axis.
 |
 |  is_transform_set(self)
 |      Return whether the Artist has an explicitly set transform.
 |
 |      This is *True* after `.set_transform` has been called.
 |
 |  pchanged(self)
 |      Call all of the registered callbacks.
 |
 |      This function is triggered internally when a property is changed.
 |
 |      See Also
 |      --------
 |      add_callback
 |      remove_callback
 |
 |  pick(self, mouseevent)
 |      Process a pick event.
 |
 |      Each child artist will fire a pick event if *mouseevent* is over
 |      the artist and the artist has picker set.
 |
 |      See Also
 |      --------
 |      set_picker, get_picker, pickable
 |
 |  pickable(self)
 |      Return whether the artist is pickable.
 |
 |      See Also
 |      --------
 |      set_picker, get_picker, pick
 |
 |  properties(self)
 |      Return a dictionary of all the properties of the artist.
 |
 |  remove(self)
 |      Remove the artist from the figure if possible.
 |
 |      The effect will not be visible until the figure is redrawn, e.g.,
 |      with `.FigureCanvasBase.draw_idle`.  Call `~.axes.Axes.relim` to
 |      update the axes limits if desired.
 |
 |      Note: `~.axes.Axes.relim` will not see collections even if the
 |      collection was added to the axes with *autolim* = True.
 |
 |      Note: there is no support for removing the artist's legend entry.
 |
 |  remove_callback(self, oid)
 |      Remove a callback based on its observer id.
 |
 |      See Also
 |      --------
 |      add_callback
 |
 |  set(self, **kwargs)
 |      A property batch setter.  Pass *kwargs* to set properties.
 |
 |  set_agg_filter(self, filter_func)
 |      Set the agg filter.
 |
 |      Parameters
 |      ----------
 |      filter_func : callable
 |          A filter function, which takes a (m, n, 3) float array and a dpi
 |          value, and returns a (m, n, 3) array.
 |
 |          .. ACCEPTS: a filter function, which takes a (m, n, 3) float array
 |              and a dpi value, and returns a (m, n, 3) array
 |
 |  set_alpha(self, alpha)
 |      Set the alpha value used for blending - not supported on all backends.
 |
 |      Parameters
 |      ----------
 |      alpha : float or None
 |
 |  set_animated(self, b)
 |      Set the artist's animation state.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_contains(self, picker)
 |      [*Deprecated*] Define a custom contains syntax for the artist.
 |
 |      The provided callable replaces the default `.contains` method
 |      of the artist.
 |
 |      Parameters
 |      ----------
 |      picker : callable
 |          A custom picker function to evaluate if an event is within the
 |          artist. The function must have the signature::
 |
 |              def contains(artist: Artist, event: MouseEvent) -> bool, dict
 |
 |          that returns:
 |
 |          - a bool indicating if the event is within the artist
 |          - a dict of additional information. The dict should at least
 |            return the same information as the default ``contains()``
 |            implementation of the respective artist, but may provide
 |            additional information.
 |
 |      Notes
 |      -----
 |      .. deprecated:: 3.3
 |
 |  set_gid(self, gid)
 |      Set the (group) id for the artist.
 |
 |      Parameters
 |      ----------
 |      gid : str
 |
 |  set_in_layout(self, in_layout)
 |      Set if artist is to be included in layout calculations,
 |      E.g. :doc:`/tutorials/intermediate/constrainedlayout_guide`,
 |      `.Figure.tight_layout()`, and
 |      ``fig.savefig(fname, bbox_inches='tight')``.
 |
 |      Parameters
 |      ----------
 |      in_layout : bool
 |
 |  set_label(self, s)
 |      Set a label that will be displayed in the legend.
 |
 |      Parameters
 |      ----------
 |      s : object
 |          *s* will be converted to a string by calling `str`.
 |
 |  set_path_effects(self, path_effects)
 |      Set the path effects.
 |
 |      Parameters
 |      ----------
 |      path_effects : `.AbstractPathEffect`
 |
 |  set_picker(self, picker)
 |      Define the picking behavior of the artist.
 |
 |      Parameters
 |      ----------
 |      picker : None or bool or callable
 |          This can be one of the following:
 |
 |          - *None*: Picking is disabled for this artist (default).
 |
 |          - A boolean: If *True* then picking will be enabled and the
 |            artist will fire a pick event if the mouse event is over
 |            the artist.
 |
 |          - A function: If picker is callable, it is a user supplied
 |            function which determines whether the artist is hit by the
 |            mouse event::
 |
 |              hit, props = picker(artist, mouseevent)
 |
 |            to determine the hit syntax.  if the mouse event is over the
 |            artist, return *hit=True* and props is a dictionary of
 |            properties you want added to the PickEvent attributes.
 |
 |          - *deprecated*: For `.Line2D` only, *picker* can also be a float
 |            that sets the tolerance for checking whether an event occurred
 |            "on" the line; this is deprecated.  Use `.Line2D.set_pickradius`
 |            instead.
 |
 |  set_rasterized(self, rasterized)
 |      Force rasterized (bitmap) drawing in vector backend output.
 |
 |      Defaults to None, which implies the backend's default behavior.
 |
 |      Parameters
 |      ----------
 |      rasterized : bool or None
 |
 |  set_sketch_params(self, scale=None, length=None, randomness=None)
 |      Sets the sketch parameters.
 |
 |      Parameters
 |      ----------
 |      scale : float, optional
 |          The amplitude of the wiggle perpendicular to the source
 |          line, in pixels.  If scale is `None`, or not provided, no
 |          sketch filter will be provided.
 |      length : float, optional
 |           The length of the wiggle along the line, in pixels
 |           (default 128.0)
 |      randomness : float, optional
 |          The scale factor by which the length is shrunken or
 |          expanded (default 16.0)
 |
 |          .. ACCEPTS: (scale: float, length: float, randomness: float)
 |
 |  set_snap(self, snap)
 |      Set the snapping behavior.
 |
 |      Snapping aligns positions with the pixel grid, which results in
 |      clearer images. For example, if a black line of 1px width was
 |      defined at a position in between two pixels, the resulting image
 |      would contain the interpolated value of that line in the pixel grid,
 |      which would be a grey value on both adjacent pixel positions. In
 |      contrast, snapping will move the line to the nearest integer pixel
 |      value, so that the resulting image will really contain a 1px wide
 |      black line.
 |
 |      Snapping is currently only supported by the Agg and MacOSX backends.
 |
 |      Parameters
 |      ----------
 |      snap : bool or None
 |          Possible values:
 |
 |          - *True*: Snap vertices to the nearest pixel center.
 |          - *False*: Do not modify vertex positions.
 |          - *None*: (auto) If the path contains only rectilinear line
 |            segments, round to the nearest pixel center.
 |
 |  set_transform(self, t)
 |      Set the artist transform.
 |
 |      Parameters
 |      ----------
 |      t : `.Transform`
 |
 |  set_url(self, url)
 |      Set the url for the artist.
 |
 |      Parameters
 |      ----------
 |      url : str
 |
 |  set_visible(self, b)
 |      Set the artist's visibility.
 |
 |      Parameters
 |      ----------
 |      b : bool
 |
 |  set_zorder(self, level)
 |      Set the zorder for the artist.  Artists with lower zorder
 |      values are drawn first.
 |
 |      Parameters
 |      ----------
 |      level : float
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from matplotlib.artist.Artist:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)
 |
 |  axes
 |      The `~.axes.Axes` instance the artist resides in, or *None*.
 |
 |  mouseover
 |      If this property is set to *True*, the artist will be queried for
 |      custom context information when the mouse cursor moves over it.
 |
 |      See also :meth:`get_cursor_data`, :class:`.ToolCursorPosition` and
 |      :class:`.NavigationToolbar2`.
 |
 |  stale
 |      Whether the artist is 'stale' and needs to be re-drawn for the output
 |      to match the internal state of the artist.
 |
 |  sticky_edges
 |      ``x`` and ``y`` sticky edge lists for autoscaling.
 |
 |      When performing autoscaling, if a data limit coincides with a value in
 |      the corresponding sticky_edges list, then no margin will be added--the
 |      view limit "sticks" to the edge. A typical use case is histograms,
 |      where one usually expects no margin on the bottom edge (0) of the
 |      histogram.
 |
 |      This attribute cannot be assigned to; however, the ``x`` and ``y``
 |      lists can be modified in place as needed.
 |
 |      Examples
 |      --------
 |      >>> artist.sticky_edges.x[:] = (xmin, xmax)
 |      >>> artist.sticky_edges.y[:] = (ymin, ymax)
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from _AnnotationBase:
 |
 |  draggable(self, state=None, use_blit=False)
 |      Set whether the annotation is draggable with the mouse.
 |
 |      Parameters
 |      ----------
 |      state : bool or None
 |          - True or False: set the draggability.
 |          - None: toggle the draggability.
 |
 |      Returns
 |      -------
 |      DraggableAnnotation or None
 |          If the annotation is draggable, the corresponding
 |          `.DraggableAnnotation` helper is returned.
 |
 |  get_annotation_clip(self)
 |      Return the annotation's clipping behavior.
 |
 |      See `set_annotation_clip` for the meaning of return values.
 |
 |  set_annotation_clip(self, b)
 |      Set the annotation's clipping behavior.
 |
 |      Parameters
 |      ----------
 |      b : bool or None
 |          - True: the annotation will only be drawn when ``self.xy`` is
 |            inside the axes.
 |          - False: the annotation will always be drawn regardless of its
 |            position.
 |          - None: the ``self.xy`` will be checked only if *xycoords* is
 |            "data".

    """

    @staticmethod
    def annotate():
        """
annotate(text, xy, *args, **kwargs)

    method of matplotlib.axes._subplots.AxesSubplot instance
    Annotate the point *xy* with text *text*.

    In the simplest form, the text is placed at *xy*.

    Optionally, the text can be displayed in another position *xytext*.
    An arrow pointing from the text to the annotated point *xy* can then
    be added by defining *arrowprops*.

    Parameters
    ----------
    text : str
        The text of the annotation.  *s* is a deprecated synonym for this
        parameter.

    xy : (float, float)
        The point *(x, y)* to annotate. The coordinate system is determined
        by *xycoords*.

    xytext : (float, float), default: *xy*
        The position *(x, y)* to place the text at. The coordinate system
        is determined by *textcoords*.

    xycoords : str or `.Artist` or `.Transform` or callable or (float, float), default: 'data'

        The coordinate system that *xy* is given in. The following types
        of values are supported:

        - One of the following strings:

          =================   =============================================
          Value               Description
          =================   =============================================
          'figure points'     Points from the lower left of the figure
          'figure pixels'     Pixels from the lower left of the figure
          'figure fraction'   Fraction of figure from lower left
          'axes points'       Points from lower left corner of axes
          'axes pixels'       Pixels from lower left corner of axes
          'axes fraction'     Fraction of axes from lower left
          'data'              Use the coordinate system of the object being
                              annotated (default)
          'polar'             *(theta, r)* if not native 'data' coordinates
          =================   =============================================

        - An `.Artist`: *xy* is interpreted as a fraction of the artist's
          `~matplotlib.transforms.Bbox`. E.g. *(0, 0)* would be the lower
          left corner of the bounding box and *(0.5, 1)* would be the
          center top of the bounding box.

        - A `.Transform` to transform *xy* to screen coordinates.

        - A function with one of the following signatures::

            def transform(renderer) -> Bbox
            def transform(renderer) -> Transform

          where *renderer* is a `.RendererBase` subclass.

          The result of the function is interpreted like the `.Artist` and
          `.Transform` cases above.

        - A tuple *(xcoords, ycoords)* specifying separate coordinate
          systems for *x* and *y*. *xcoords* and *ycoords* must each be
          of one of the above described types.

        See :obj:`plotting-guide-annotation` for more details.

    textcoords : str or `.Artist` or `.Transform` or callable or (float, float), default: value of *xycoords*
        The coordinate system that *xytext* is given in.

        All *xycoords* values are valid as well as the following
        strings:

        =================   =========================================
        Value               Description
        =================   =========================================
        'offset points'     Offset (in points) from the *xy* value
        'offset pixels'     Offset (in pixels) from the *xy* value
        =================   =========================================

    arrowprops : dict, optional
        The properties used to draw a `.FancyArrowPatch` arrow between the
        positions *xy* and *xytext*.

        If *arrowprops* does not contain the key 'arrowstyle' the
        allowed keys are:

        ==========   ======================================================
        Key          Description
        ==========   ======================================================
        width        The width of the arrow in points
        headwidth    The width of the base of the arrow head in points
        headlength   The length of the arrow head in points
        shrink       Fraction of total length to shrink from both ends
        ?            Any key to :class:`matplotlib.patches.FancyArrowPatch`
        ==========   ======================================================

        If *arrowprops* contains the key 'arrowstyle' the
        above keys are forbidden.  The allowed values of
        ``'arrowstyle'`` are:

        ============   =============================================
        Name           Attrs
        ============   =============================================
        ``'-'``        None
        ``'->'``       head_length=0.4,head_width=0.2
        ``'-['``       widthB=1.0,lengthB=0.2,angleB=None
        ``'|-|'``      widthA=1.0,widthB=1.0
        ``'-|>'``      head_length=0.4,head_width=0.2
        ``'<-'``       head_length=0.4,head_width=0.2
        ``'<->'``      head_length=0.4,head_width=0.2
        ``'<|-'``      head_length=0.4,head_width=0.2
        ``'<|-|>'``    head_length=0.4,head_width=0.2
        ``'fancy'``    head_length=0.4,head_width=0.4,tail_width=0.4
        ``'simple'``   head_length=0.5,head_width=0.5,tail_width=0.2
        ``'wedge'``    tail_width=0.3,shrink_factor=0.5
        ============   =============================================

        Valid keys for `~matplotlib.patches.FancyArrowPatch` are:

        ===============  ==================================================
        Key              Description
        ===============  ==================================================
        arrowstyle       the arrow style
        connectionstyle  the connection style
        relpos           default is (0.5, 0.5)
        patchA           default is bounding box of the text
        patchB           default is None
        shrinkA          default is 2 points
        shrinkB          default is 2 points
        mutation_scale   default is text size (in points)
        mutation_aspect  default is 1.
        ?                any key for :class:`matplotlib.patches.PathPatch`
        ===============  ==================================================

        Defaults to None, i.e. no arrow is drawn.

    annotation_clip : bool or None, default: None
        Whether to draw the annotation when the annotation point *xy* is
        outside the axes area.

        - If *True*, the annotation will only be drawn when *xy* is
          within the axes.
        - If *False*, the annotation will always be drawn.
        - If *None*, the annotation will only be drawn when *xy* is
          within the axes and *xycoords* is 'data'.

    **kwargs
        Additional kwargs are passed to `~matplotlib.text.Text`.

    Returns
    -------
    `.Annotation`

    See Also
    --------
    :obj:`plotting-guide-annotation`
        """
        fig, ax = plt.subplots()
        x = np.arange(0, 2*np.pi, 0.1)
        y = np.sin(x)
        ax.plot(x, y)

        # annotation: pi/10, set arrow_width=2
        an = ax.annotate(text=r'$sin(\frac{\pi}{10})$',     # 注释文本
                         xy=(np.pi/10, np.sin(np.pi/10)),   # 注释点坐标
                         xytext=(np.pi/2, 0.3),             # 注释文本坐标
                         arrowprops=dict(width=0.3,
                                         headwidth=3.5,
                                         headlength=8.5,
                                         connectionstyle='arc3,rad=-0.5',
                                         color='y'
                                         ),
                         bbox={'alpha': 0.5},
                         )

        # annotation: pi/3, set arrow_style='fancy'
        an = ax.annotate(text=r'$sin(\frac{3\pi}{2})$',
                         xy=(np.pi*3/2, np.sin(np.pi*3/2)),
                         xytext=(np.pi*3/2-0.2, 0),             # 注释框坐标，x坐标左移
                         arrowprops=dict(arrowstyle='fancy',
                                         color='r'
                                         ),                     # 箭头设置，使用arrowstyle设置固定样式
                         bbox={'facecolor': '#74C476',          # 填充色
                               'edgecolor': 'b',                # 外框色
                               'alpha': 0.3,                    # 框透明度
                               'pad': 0.6,                      # 本文与框周围距离
                               'boxstyle': 'sawtooth'           # 文本框样式
                               }
                         )

        ax.set_ylim(-1.01, 1.01)
        ax.set_xlim(0, 2*np.pi-0.1)

        return an

    def annotate_cross_axes(self):
        """annotate boject in ax1 from ax2"""
        from matplotlib.text import OffsetFrom
        fig, (ax1, ax2) = plt.subplots(2)
        bbox_params = dict(boxstyle="round", fc="lightgreen")
        ax2.annotate(
            text='Cupid arrow start from ax2',
            xy=(0.85, 0.3),
            xycoords=ax1.transData,
            xytext=(10, 10),
            textcoords=OffsetFrom(ax2.bbox, (0, 0), "points"),
            ha="left",
            va="bottom",
            bbox=bbox_params,
            arrowprops=dict(connectionstyle="arc3,rad=0.5")
            )

class DemoColor:

    @staticmethod
    def scatter_rgb():
        colors1 = [(0, 0, 1), (1, 0, 0), (0, 1, 0)]
        colors2 = [(0, 0, 1, 1), (1, 0, 0, 1), (0, 1, 0, 1)]
        colors3 = [(0, 0, 1, 1), (1, 0, 0, 0.6), (0, 1, 0, 0.3)]

        centerx = [0.3333, 0.99999/2, 0.6666]
        centery = [0.3333, 0.28887+0.3333, 0.3333]

        fig, ax = plt.subplots(1, 3, figsize=(12, 4))
        ax[0].pie([1]*len(colors1), colors=colors1, labels=colors1)
        ax[0].set_xlabel('RGB: tuples')

        ax[1].scatter(centerx, centery, c=colors2, s=10000)
        ax[1].text(0.4, -0.01, 'RGBA: alpha = 1')

        ax[2].scatter(centerx, centery, c=colors3, s=10000)
        ax[2].text(0.4, -0.01, 'RGBA: alpha = {}, {}, {}'.format(1, 0.6, 0.3))

        for j in [1, 2]:
            ax[j].set(xlim=[0, 1], ylim=[0, 1])
            ax[j].set_frame_on(False)
            ax[j].xaxis.set_visible(False)
            ax[j].yaxis.set_visible(False)

    @staticmethod
    def exp_rgb_tuple():
        colors = [(0, 0, 1), (1, 0, 0), (0, 1, 0)]
        fig, ax = plt.subplots()
        ax.pie(x=[1]*len(colors), colors=colors, labels=colors)

    @staticmethod
    def exp_rgb_hexstr():
        colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd',
                  '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf']
        fig, ax = plt.subplots()
        ax.bar(range(len(colors)), range(1, 2*len(colors)+1, 2), color=colors, tick_label=colors)
        # ax.tick_params(axis='x', labelrotation=90)

    @staticmethod
    def exp_gray_float():
        colors = ['{:.4f}'.format(v) for v in np.linspace(0.1, 0.9, 9)]
        fig, ax = plt.subplots()
        ax.pie(x=[1]*len(colors), colors=colors, labels=colors)
        print(colors)

    @staticmethod
    def exp_single_char_colors():
        single_char_colors = ['r', 'g', 'b', 'c', 'm', 'y', 'k', 'w']
        fig, ax = plt.subplots()
        ax.pie(x=[1] * 8, colors=single_char_colors, labels=single_char_colors)

    @staticmethod
    def exp_base_colors():
        base_colors = list(mpl.colors.BASE_COLORS.keys())
        fig, ax = plt.subplots()
        ax.pie(x=[1]*8, colors=base_colors, labels=base_colors)

    @staticmethod
    def exp_tableau():
        # tab_colors = ['tab:blue', 'tab:orange', 'tab:green', 'tab:red', 'tab:purple',
        #               'tab:brown', 'tab:pink', 'tab:gray', 'tab:olive', 'tab:cyan']
        tab_colors = ['tab:red', 'tab:green', 'tab:blue', 'tab:cyan', 'tab:brown', 'tab:pink', 'tab:olive',
                      'yellow', 'k']
        fig, ax = plt.subplots()
        ax.pie(range(1, len(tab_colors)+1), colors=tab_colors, labels=[c for c in tab_colors])

        # 混合使用其他颜色名称
        tab_colors = ['tab:red', 'tab:green', 'tab:blue', 'tab:cyan', 'tab:pink', 'tab:olive', 'y', 'k']
        fig, ax = plt.subplots()
        ax.pie(range(1, len(tab_colors)+1), colors=tab_colors, labels=[c for c in tab_colors])

    @staticmethod
    def exp_css4():
        # import matplotlib._color_data as mcd
        # css4_colors = mpl.colors.CSS4_COLORS
        data_num = 30
        colors = list(mpl.colors.CSS4_COLORS.keys())
        x = np.linspace(0, 2*np.pi, data_num)
        y = np.sin(x)
        plt.scatter(x, y, c=colors[10:data_num+10], s=500)

        # plt.pie(range(1, 11), colors=colors10, labels=colors10)
        # for c in colors10:
        #     print('{:<20s} {}'.format(c, css4_colors[c]))

    @staticmethod
    def exp_xkcd(max_num=10):
        # import matplotlib._color_data as mcd
        xkcd_colors = mpl.colors.XKCD_COLORS
        colors = list(xkcd_colors.keys())[:max_num]
        plt.pie(range(1, 11), colors=list(xkcd_colors.keys())[:max_num])
        for c in colors:
            print('{:<20s} {}'.format(c, xkcd_colors[c]))

    @staticmethod
    def exp_cn():
        from cycler import cycler
        fig, ax = plt.subplots(1, 2, figsize=(10, 5))

        # 使用缺省全局设置颜色
        mpl.rcdefaults()
        rc_colors = mpl.rcParams['axes.prop_cycle']
        cn_colors = ['C' + str(i) for i in range(len(rc_colors))]
        labels = [c+':'+v for c, v in zip(cn_colors, rc_colors.by_key()['color'])]
        ax[0].pie(x=[1] * len(rc_colors), colors=cn_colors, labels=labels)
        # ax[0].text(-0.7, 1.3, 'default prop_cycle', fontsize=16)
        ax[0].set_title('default prop_cycle', loc='center', fontsize='xx-large')

        # 修改Axes.rcParams["axes.prop_cycle"]的颜色设置
        colors5 = [c for c in list(mpl.colors.CSS4_COLORS.keys())[:5]]
        new_cycler = cycler(color=colors5)
        mpl.rc('axes', prop_cycle=new_cycler)
        cn_colors = ['C' + str(i) for i in range(len(colors5))]
        labels = [c+':'+v for c, v in zip(cn_colors, colors5)]
        ax[1].pie(x=[1]*len(colors5), colors=cn_colors, labels=labels)
        # ax[1].text(-0.7, 1.3, 'new prop_cycle', fontsize=16)
        ax[1].set_title('new prop_cycle', loc='center', fontsize='xx-large')

        # 使用Axes设置子图cycler，不能用于CN颜色命名引用
        # fig, ax = plt.subplots()
        # color_num = 12
        # ax_cycler = cycler(color=[c for c in list(mpl.colors.CSS4_COLORS.keys())[:color_num]])
        # ax.set_prop_cycle(ax_cycler)        # 指定修改ax1，只对子图ax1生效
        # cn_colors = ['C' + str(i) for i in range(color_num)]
        # # still get colors CN from rcParams['axes.prop_cycle']!
        # ax.pie(x=[1] * color_num, colors=cn_colors, labels=cn_colors)

    @staticmethod
    def list_colors_buildin():
        import matplotlib.colors as cl
        def print_colosr(map, num=11, name='BASE_COLORS'):
            print('='*60)
            print('{}({})'.format(name, len(map)))
            print('-'*60)
            map_keys_list = list(map.keys())
            for j, k in enumerate(map_keys_list[:num]):
                print('[{}] {:<25s}{}'.format(j+1, k, map[k]))
            if len(map) > num:
                print('. .'*3)
                print('[{}] {:<25s}{}'.format(len(map), map_keys_list[-1], map[map_keys_list[-1]]))
        print_colosr(cl.BASE_COLORS)
        print_colosr(cl.TABLEAU_COLORS, name='TABLEAU_COLORS')
        print_colosr(cl.CSS4_COLORS, 10, name='CSS4_COLORS')
        print_colosr(cl.XKCD_COLORS, 10, name='XKCD_COLORS')
        # print_colosr(cl.cnames, 10, name='cnames')

        print("="*60)
        full_colors = cl._colors_full_map
        print('base = ', len([c for c in full_colors if len(c) == 1]))
        print('tableau = ', len([c for c in full_colors if 'tab:' in c]))
        print('xkcd = ', len([c for c in full_colors if 'xkcd' in c]))
        print('css4 = ', len([c for c in full_colors
                              if (len(c) > 1) and ('tab:' not in c) and ('xkcd' not in c)]))
        print('cnames = ', len([c for c in full_colors if c in cl.cnames]))
        print('_colors_full_map = base+tab+xkcd+css4 = {}'.format(len(full_colors)))

        # identify: cnames == CSS4
        # for c in cl.cnames:
        #     if c not in cl.CSS4_COLORS:
        #         print(c)

    @staticmethod
    def plot_buildin_color_tables(colors_table=mpl.colors.BASE_COLORS, title='', sort_colors=True, emptycols=0):
        """
        以表格方式显示内置颜色空间的颜色，通过计算位置确定每个单元的绘图
        缺省设置为4列，多行。颜色较少时可以通过emptycols减少列数
        表格的每个单元（cell）显示颜色名称和颜色矩形
        """

        from matplotlib.patches import Rectangle
        import matplotlib.colors as mcolors

        cell_width = 212        # 设置展示颜色的格子的宽度（单位为像素点）
        cell_height = 22        # 设置展示颜色的格子的高度
        swatch_width = 48       # 设置展示颜色色彩块的宽度
        margin = 12             # 格子直接的间隙
        topmargin = 40          # 顶端的间隙

        # Sort colors by hue, saturation, value and name.
        # 使用hsv（色调、饱和度、量度）方式排序颜色表
        hsv = mcolors.rgb_to_hsv
        rgb = mcolors.to_rgb
        if sort_colors is True:
            # 在颜色表中取出名称和对应颜色值,先转为rgb，再转为hsv, 生成元组（hsv, name）, 再进行排序
            by_hsv = sorted((tuple(hsv(rgb(color))), name) for name, color in colors_table.items())
            # 生成排序后的颜色名称列表
            names = [name for hsv, name in by_hsv]
        else:
            # 直接从字典中取出键（颜色名称）
            names = list(colors_table)

        n = len(names)                                      # 颜色总数
        ncols = 4 - emptycols                               # 颜色列数
        nrows = n // ncols + int(n % ncols > 0)             # 颜色行数
        width = cell_width * 4 + 2 * margin                 # 计算每个颜色显示占用宽度（包括两边间隙）
        height = cell_height * nrows + margin + topmargin   # 计算占用高度
        dpi = 72                                            # 每英寸点数

        # 使用预定宽度和高度创建画板、调整间隙、设置范围、隐含坐标轴、设置标题
        fig, ax = plt.subplots(figsize=(width / dpi, height / dpi), dpi=dpi)
        # 调整子图间隙
        fig.subplots_adjust(margin/width, margin/height,
                            (width-margin)/width, (height-topmargin)/height)
        # 设置显示范围
        ax.set_xlim(0, cell_width * 4)
        ax.set_ylim(cell_height * (nrows - 0.5), -cell_height / 2.)

        # 隐藏坐标轴线及刻度
        ax.yaxis.set_visible(False)
        ax.xaxis.set_visible(False)
        ax.set_axis_off()

        # 设置标题（靠左）
        ax.set_title(title, fontsize=24, loc="left", pad=10)
        # 在单元位置显示各个颜色
        for i, name in enumerate(names):
            row = i % nrows             # 计算当前绘图行
            col = i // nrows            # 计算当前绘图列
            y = row * cell_height       # 计算绘图格子的高度

            swatch_start_x = cell_width * col                   # 计算颜色图形x位置
            text_pos_x = cell_width * col + swatch_width + 7    # 计算颜色名称x位置

            # 绘制颜色名称
            ax.text(text_pos_x, y, name, fontsize=14,
                    horizontalalignment='left',
                    verticalalignment='center')

            # 绘制颜色矩形，并加入子图
            ax.add_patch(
                Rectangle(xy=(swatch_start_x, y - 9), width=swatch_width,
                          height=18, facecolor=colors_table[name], edgecolor='0.7')
                )
        return fig

    @staticmethod
    def figure_buildin_color_tables(xkcd=False):
        """
        display buildin-colors(base, tableau, css4, xkcd) by calling plot_buildin_color_tables
        xkcd color_space is too large to create,
        set xkcd=True if being sure to create color pallet
        """

        import matplotlib.colors as mcolors

        # 生成BASE_COLORS颜色表图形
        DemoColor.plot_buildin_color_tables(
            mcolors.BASE_COLORS,
            title="Base Colors",
            sort_colors=False,
            emptycols=1)

        # 生成TABLEAU_COLORS颜色表图形
        DemoColor.plot_buildin_color_tables(
            mcolors.TABLEAU_COLORS,
            title="Tableau Palette",
            sort_colors=False, emptycols=2)

        # 生成CSS4_COLORS颜色表图形
        DemoColor.plot_buildin_color_tables(
            mcolors.CSS4_COLORS,
            title="CSS Colors",
            sort_colors=False
        )

        # 下面生成XKCD颜色表的代码可以选择执行，因为该表中颜色较多，会产生一个很大的绘制图形
        # Optionally plot the XKCD colors (Caution: will produce large figure)
        if xkcd:
            xkcd_fig = DemoColor.plot_buildin_color_tables(mcolors.XKCD_COLORS, "XKCD Colors")
            xkcd_fig.savefig("XKCD_Colors.png")

    @staticmethod
    def show_cnames_colors():
        """
        show cnames colors in figure
        """

        import matplotlib.patches as patches
        import matplotlib.colors as colors
        import math

        fig, ax = plt.subplots()

        # 隐藏坐标轴线及刻度
        ax.yaxis.set_visible(False)
        ax.xaxis.set_visible(False)
        ax.set_axis_off()

        side_ratio = 1/2.5
        side_count = math.ceil(math.sqrt(len(colors.cnames)))
        colnum = side_count * side_ratio
        rownum = side_count / side_ratio
        x = 0
        y = 0
        w = 1 / colnum
        h = 1 / rownum
        ax.set_ylim(-h, 1)

        for c in colors.cnames:
            pos = (x / colnum, 1-y / rownum-h)
            ax.add_patch(patches.Rectangle(pos, w*0.4, h*0.90, color=c))
            pos = (x / colnum+w*0.41, 1-y / rownum-h/1.5)
            ax.annotate(c, xy=pos)
            if y >= rownum - 1:
                x += 1
                y = 0
            else:
                y += 1

    @staticmethod
    def create_and_register_LinearSegmentColorcmap(*color_names, cmap_name=None):
        """
        Create a colormap from a list of given colors.
        Parameters:
            *color_names: some colors (Named color, HEX or RGB), used to set cmap.
            name (str): Name with which the colormap is registered.
        Returns:
            LinearSegmentedColormap registered.

        Examples:
            >>> DemoColor.create_and_register_LinearSegmentColorcmap(\
                    'darkorange', 'white', 'darkgreen', cmap_name='syntax')
        """
        if len(color_names) < 2:
            raise Exception("must to set two colors at least.")
        cmap_data = [mpl.colors.to_hex(c) for c in color_names]
        linear_cmap = mpl.colors.LinearSegmentedColormap.from_list(cmap_name, cmap_data)
        plt.register_cmap(cmap_name, linear_cmap)

        return linear_cmap


class DemoColormap:

    @staticmethod
    def cmap_scatter_data(cmap_name='Reds'):
        """
        使用有序颜色映射表表示有序数据是有效的
        而使用多色彩映射表往往不能正确展示数据的变化
        # effective:
        DemoColormap.plot_data_with_cmap('Blues')
        # not effective:
        DemoColormap.plot_data_with_cmap('seismic')
        """

        # 数据在[0, 2*np.pi]上呈现[-1, 1]范围的变化
        x = np.linspace(0, 2*np.pi, 100)
        y = np.sin(x)

        # 使用映射表Reds部分颜色，表示函数值变化
        cmap = mpl.cm.get_cmap(cmap_name)
        fig, axs = mpl.pyplot.subplots(1,2)
        axplot = axs[0].scatter(x, y, s=100, c=y, cmap=cmap)
        axs[0].set_title(r"$y = sin(x)$")
        plt.colorbar(axplot, ax=axs[0], orientation='vertical', ticks=np.linspace(-1, 1, 10))

        # 使用映射表Reds部分颜色，表示函数值变化
        cmap = mpl.cm.get_cmap(cmap_name, 3)
        axplot = axs[1].scatter(x, y, s=100, c=y, cmap=cmap)
        axs[1].set_title(r"$y = sin(x)$")
        plt.colorbar(axplot, ax=axs[1], orientation='vertical', ticks=np.linspace(-1, 1, 7))

    @staticmethod
    def cmap_imshow_data2d(cmap='Blues'):
        # 生成随机数据,5行5列,最大值1,最小值-1
        data = np.clip(np.random.randn(5, 5), -1, 1)

        fig, axs = plt.subplots(1, 4)

        # 使用默认配置
        axs[0].imshow(data)

        # 使用colormap: cool
        cmap = mpl.cm.get_cmap('cool')
        axs[1].imshow(data, cmap=cmap)

        # 增加colorbar
        cmap = mpl.cm.get_cmap('hot')
        im = axs[2].imshow(data, cmap=cmap)
        plt.colorbar(im, ax=axs[2], orientation='vertical', shrink=0.3, fraction=0.1)

        # 调整colorbar
        cmap = mpl.cm.winter
        im = axs[3].imshow(data, cmap=cmap)
        plt.colorbar(im, ticks=[-1, 0, 1], orientation='vertical', fraction=0.1, shrink=0.3)

        plt.subplots_adjust()

    @staticmethod
    def cmap_npmesh_data2d(cmap_name='hot_r'):

        # 生成网格数据
        m, n = (100, 100)
        x = np.linspace(-1, 1, m)
        y = np.linspace(-1, 1, n)
        X, Y = np.meshgrid(x, y)

        # 定义二维函数
        def f2(_x, _y):
            return 1-(_x**2 + _y**2)

        def f3(_x, _y):
            return np.sin(_x) + np.cos(_y)

        # 绘制登高线填充图形
        fig, axs = plt.subplots(2, 2)
        axs[0, 0].set(title='$z = x^{2} + y^{2}$', xlabel='X', ylabel='Y')
        axs[0, 0].contourf(X, Y, f2(X, Y), 50, alpha=0.75, cmap=cmap_name)
        axs[0, 1].set(title='$z = sin(x) + cos(y)$', xlabel='X', ylabel='Y')
        axs[0, 1].contourf(X, Y, f3(X, Y), 50, alpha=0.75, cmap=cmap_name)

        axs[1, 0].set_frame_on(False)
        axs[1, 0].set(xticks=[], yticks=[])
        ax10 = fig.add_subplot(223, projection='3d')
        ax10.plot_surface(X, Y, f2(X, Y), alpha=0.9, cmap=cmap_name)
        ax10.set(xlabel='X', ylabel='Y', zlabel='Z')

        axs[1, 1].set_frame_on(False)
        axs[1, 1].set(xticks=[], yticks=[])
        ax11 = fig.add_subplot(224, projection='3d')
        ax11.plot_surface(X, Y, f3(X, Y), cmap=cmap_name)
        ax11.set(xlabel='X', ylabel='Y', zlabel='Z')

    @staticmethod
    def cmap_imshow_image(cmap_name='hot'):
        cmap_name1 = 'viridis'
        cmap_name2 = cmap_name
        import matplotlib.cbook as cbook
        with cbook.get_sample_data('ct.raw.gz') as f:
            s = f.read()
        A = np.frombuffer(s, np.uint16).astype(float).reshape((512, 512))
        A /= A.max()

        fig, axs = plt.subplots(1, 2)
        extent = (0, 100, 0, 100)
        axs[0].imshow(A, cmap=cmap_name1, origin='upper', extent=extent)
        axs[0].set(xlabel='colormap='+cmap_name1)
        axs[1].imshow(A, cmap=cmap_name2, origin='upper', extent=extent)
        axs[1].set(xlabel='colormap='+cmap_name2, yticks=[])

    @staticmethod
    def show_colormap(cmap=None):
        if isinstance(cmap, str):
            cmap = plt.cm.get_cmap(cmap)
        elif not isinstance(cmap, mpl.colors.Colormap):
            raise ValueError
        colors = cmap(np.arange(cmap.N))
        fig, ax = plt.subplots(1, figsize=(6, 2), subplot_kw=dict(xticks=[], yticks=[]))
        ax.imshow([colors], extent=[0.5, 10, 0, 1])
        # xloc = (len(cmap.name)+1)*12/72
        ax.text(0.5, 1.2, cmap.name)
        # ax.set_xlabel(cmap.name)

    @staticmethod
    def linear_cmap_init():
        cdict = {
            'red': [(0.0, 0.0, 0.0),
                    (0.5, 1.0, 1.0),
                    (1.0, 1.0, 1.0)],
            'green': [(0.0, 0.0, 0.0),
                      (0.25, 0.0, 0.0),
                      (0.75, 1.0, 1.0),
                      (1.0, 1.0, 1.0)],
            'blue': [(0.0, 0.0, 0.0),
                     (0.5, 0.0, 0.0),
                     (1.0, 1.0, 1.0)]
        }
        mycmap = mpl.colors.LinearSegmentedColormap(
            name='mycolormap', segmentdata=cdict)

        x = np.arange(0, np.pi*2, 0.1)
        y = np.sin(x)
        fig, ax = plt.subplots()
        ax.scatter(x, y, c=y, cmap=mycmap)
        ax.xaxis.grid(True, 'major')
        ax.yaxis.grid(True, 'major')
        ax.set(xlim=(0, np.pi*2), ylim=(-1.1, 1.1), facecolor='lightgreen')

        DemoColormap.show_colormap(mycmap)

    @staticmethod
    def linear_cmap_from_list_rgb():
        """
        from_list(name, colors, N=256, gamma=1.0)

        Create a `LinearSegmentedColormap` from a list of colors.

        Parameters
        ----------
        name : str
            The name of the colormap.
        colors : array-like of colors or array-like of (value, color)
            If only colors are given, they are equidistantly mapped from the
            range :math:`[0, 1]`; i.e. 0 maps to ``colors[0]`` and 1 maps to
            ``colors[-1]``.
            If (value, color) pairs are given, the mapping is from *value*
            to *color*. This can be used to divide the range unevenly.
        N : int
            The number of rgb quantization levels.
        gamma : float
        """

        # 由颜色值（RGB三元组）创建映射表
        cmap_name = 'colormap1'
        cmap_colors = [(0.9, 0.1, 0.1), (0.1, 0.9, 0.1), (0.1, 0.1, 0.9)]
        cmap1 = mpl.colors.LinearSegmentedColormap.from_list(name=cmap_name, colors=cmap_colors)
        DemoColormap.show_colormap(cmap1)

    @staticmethod
    def linear_cmap_from_list_val_rgb():
        # 由映射值、颜色值二元组（value, color）创建映射表
        cmap_name = 'colormap2'
        cmap_colors = [(0, (0.9, 0.1, 0.1)), (0.2, (0.1, 0.9, 0.1)), (1, (0.1, 0.1, 0.9))]
        cmap2 = mpl.colors.LinearSegmentedColormap.from_list(name=cmap_name, colors=cmap_colors)
        DemoColormap.show_colormap(cmap2)


class DemoImshow:

    """
    imshow(X, cmap=None, norm=None, aspect=None, interpolation=None, alpha=None, vmin=None, vmax=None,
           origin=None, extent=None, *, filternorm=True, filterrad=4.0, resample=None, url=None, data=None,
           **kwargs)
        Display data as an image, i.e., on a 2D regular raster.

        The input may either be actual RGB(A) data, or 2D scalar data, which
        will be rendered as a pseudocolor image. For displaying a grayscale
        image set up the color mapping using the parameters
        ``cmap='gray', vmin=0, vmax=255``.

        The number of pixels used to render an image is set by the axes size
        and the *dpi* of the figure. This can lead to aliasing artifacts when
        the image is resampled because the displayed image size will usually
        not match the size of *X* (see
        :doc:`/gallery/images_contours_and_fields/image_antialiasing`).
        The resampling can be controlled via the *interpolation* parameter
        and/or :rc:`image.interpolation`.

        Parameters
        ----------
        X : array-like or PIL image
            The image data. Supported array shapes are:

            - (M, N): an image with scalar data. The values are mapped to
              colors using normalization and a colormap. See parameters *norm*,
              *cmap*, *vmin*, *vmax*.
            - (M, N, 3): an image with RGB values (0-1 float or 0-255 int).
            - (M, N, 4): an image with RGBA values (0-1 float or 0-255 int),
              i.e. including transparency.

            The first two dimensions (M, N) define the rows and columns of
            the image.

            Out-of-range RGB(A) values are clipped.

        cmap : str or `~matplotlib.colors.Colormap`, default: :rc:`image.cmap`
            The Colormap instance or registered colormap name used to map
            scalar data to colors. This parameter is ignored for RGB(A) data.

        norm : `~matplotlib.colors.Normalize`, optional
            The `.Normalize` instance used to scale scalar data to the [0, 1]
            range before mapping to colors using *cmap*. By default, a linear
            scaling mapping the lowest value to 0 and the highest to 1 is used.
            This parameter is ignored for RGB(A) data.

        aspect : {'equal', 'auto'} or float, default: :rc:`image.aspect`
            The aspect ratio of the axes.  This parameter is particularly
            relevant for images since it determines whether data pixels are
            square.

            This parameter is a shortcut for explicitly calling
            `.Axes.set_aspect`. See there for further details.

            - 'equal': Ensures an aspect ratio of 1. Pixels will be square
              (unless pixel sizes are explicitly made non-square in data
              coordinates using *extent*).
            - 'auto': The axes is kept fixed and the aspect is adjusted so
              that the data fit in the axes. In general, this will result in
              non-square pixels.

        interpolation : str, default: :rc:`image.interpolation`
            The interpolation method used.

            Supported values are 'none', 'antialiased', 'nearest', 'bilinear',
            'bicubic', 'spline16', 'spline36', 'hanning', 'hamming', 'hermite',
            'kaiser', 'quadric', 'catrom', 'gaussian', 'bessel', 'mitchell',
            'sinc', 'lanczos'.

            If *interpolation* is 'none', then no interpolation is performed
            on the Agg, ps, pdf and svg backends. Other backends will fall back
            to 'nearest'. Note that most SVG renderers perform interpolation at
            rendering and that the default interpolation method they implement
            may differ.

            If *interpolation* is the default 'antialiased', then 'nearest'
            interpolation is used if the image is upsampled by more than a
            factor of three (i.e. the number of display pixels is at least
            three times the size of the data array).  If the upsampling rate is
            smaller than 3, or the image is downsampled, then 'hanning'
            interpolation is used to act as an anti-aliasing filter, unless the
            image happens to be upsampled by exactly a factor of two or one.

            See
            :doc:`/gallery/images_contours_and_fields/interpolation_methods`
            for an overview of the supported interpolation methods, and
            :doc:`/gallery/images_contours_and_fields/image_antialiasing` for
            a discussion of image antialiasing.

            Some interpolation methods require an additional radius parameter,
            which can be set by *filterrad*. Additionally, the antigrain image
            resize filter is controlled by the parameter *filternorm*.

        alpha : float or array-like, optional
            The alpha blending value, between 0 (transparent) and 1 (opaque).
            If *alpha* is an array, the alpha blending values are applied pixel
            by pixel, and *alpha* must have the same shape as *X*.

        vmin, vmax : float, optional
            When using scalar data and no explicit *norm*, *vmin* and *vmax*
            define the data range that the colormap covers. By default,
            the colormap covers the complete value range of the supplied
            data. It is deprecated to use *vmin*/*vmax* when *norm* is given.

        origin : {'upper', 'lower'}, default: :rc:`image.origin`
            Place the [0, 0] index of the array in the upper left or lower
            left corner of the axes. The convention (the default) 'upper' is
            typically used for matrices and images.

            Note that the vertical axes points upward for 'lower'
            but downward for 'upper'.

            See the :doc:`/tutorials/intermediate/imshow_extent` tutorial for
            examples and a more detailed description.

        extent : floats (left, right, bottom, top), optional
            The bounding box in data coordinates that the image will fill.
            The image is stretched individually along x and y to fill the box.

            The default extent is determined by the following conditions.
            Pixels have unit size in data coordinates. Their centers are on
            integer coordinates, and their center coordinates range from 0 to
            columns-1 horizontally and from 0 to rows-1 vertically.

            Note that the direction of the vertical axis and thus the default
            values for top and bottom depend on *origin*:

            - For ``origin == 'upper'`` the default is
              ``(-0.5, numcols-0.5, numrows-0.5, -0.5)``.
            - For ``origin == 'lower'`` the default is
              ``(-0.5, numcols-0.5, -0.5, numrows-0.5)``.

            See the :doc:`/tutorials/intermediate/imshow_extent` tutorial for
            examples and a more detailed description.

        filternorm : bool, default: True
            A parameter for the antigrain image resize filter (see the
            antigrain documentation).  If *filternorm* is set, the filter
            normalizes integer values and corrects the rounding errors. It
            doesn't do anything with the source floating point values, it
            corrects only integers according to the rule of 1.0 which means
            that any sum of pixel weights must be equal to 1.0.  So, the
            filter function must produce a graph of the proper shape.

        filterrad : float > 0, default: 4.0
            The filter radius for filters that have a radius parameter, i.e.
            when interpolation is one of: 'sinc', 'lanczos' or 'blackman'.

        resample : bool, default: :rc:`image.resample`
            When *True*, use a full resampling method.  When *False*, only
            resample when the output image is larger than the input image.

        url : str, optional
            Set the url of the created `.AxesImage`. See `.Artist.set_url`.

        Returns
        -------
        `~matplotlib.image.AxesImage`

        Other Parameters
        ----------------
        **kwargs : `~matplotlib.artist.Artist` properties
            These parameters are passed on to the constructor of the
            `.AxesImage` artist.

        See Also
        --------
        matshow : Plot a matrix or an array as an image.

        Notes
        -----
        Unless *extent* is used, pixel centers will be located at integer
        coordinates. In other words: the origin will coincide with the center
        of pixel (0, 0).

        There are two common representations for RGB images with an alpha
        channel:

        -   Straight (unassociated) alpha: R, G, and B channels represent the
            color of the pixel, disregarding its opacity.
        -   Premultiplied (associated) alpha: R, G, and B channels represent
            the color of the pixel, adjusted for its opacity by multiplication.

        `~matplotlib.pyplot.imshow` expects RGB images adopting the straight
        (unassociated) alpha representation.

        .. note::
            In addition to the above described arguments, this function can take
            a *data* keyword argument. If such a *data* argument is given,
            every other argument can also be string ``s``, which is
            interpreted as ``data[s]`` (unless this raises an exception).

            Objects passed as **data** must support item access (``data[s]``) and
            membership syntax (``s in data``).
    """

    @staticmethod
    def show_images_in_subplots_tight(row=4, col=5, images=None):
        """
        show images in subplots
        tweat wspace, hspace by tight_layout
        """
        if not images:
            images = np.random.random([row*col, 512, 512])
            images = [images[i*row + j, :, :] for i in range(row) for j in range(col)]
        fig, ax = plt.subplots(row, col)
        for i in range(row):
            for j in range(col):
                ax[i, j].imshow(images[i*row+j])
                ax[i, j].set_frame_on(False)
                ax[i, j].xaxis.set_visible(False)
                ax[i, j].yaxis.set_visible(False)
        plt.tight_layout(pad=0, h_pad=0.15, w_pad=-1.4)
        plt.show()

    @staticmethod
    def show_images_in_subplots_adjust(row=4, col=5, images=None):
        """
        show images in subplots
        tweat wspace, hspace by subplots_adjust
        """
        if not images:
            images = np.random.random([row*col, 512, 512])
            images = [images[i * row + j, :, :] for i in range(row) for j in range(col)]
        # print(images[0, 0:3, 0:3])

        fig, ax = plt.subplots(row, col)
        for i in range(row):
            for j in range(col):
                images[i*row+j][0:100, 0:100] = (i*4*5 + j*10)/256
                ax[i, j].set_frame_on(False)
                ax[i, j].set(xticks=[], yticks=[])
                ax[i, j].imshow(images[i*row+j])
        plt.subplots_adjust(wspace=-0.25, hspace=0.03)

        plt.show()

    @staticmethod
    def show_images_in_imagegrid(row=4, col=5, images=None):
        """
        show iamges in ImageGrid
        """
        from mpl_toolkits.axes_grid1 import ImageGrid
        if not images:
            images = np.random.random([20, 512, 512])
            images = [images[i * row + j, :, :] for i in range(row) for j in range(col)]

        fig = plt.figure()

        grid = ImageGrid(fig, (0, 0, 1, 1),                  # (left, bottom, width, height)
                         nrows_ncols=(row, col),
                         axes_pad=0.1,
                         share_all=True,
                         cbar_set_cax=False,
                         cbar_size=0
                         )

        i = 0
        for ax in grid:
            # ax.imshow(images[i, :, :], extent=[-16, 16, -18, 18])
            ax.imshow(images[i])
            ax.set(xticks=[], yticks=[])
            # set spines off
            # ax.spines['top'].set_color('none')
            ax.spines['bottom'].set_color('none')
            ax.spines['left'].set_color('none')
            ax.spines['right'].set_color('none')
            # set spines linewidth
            ax.spines['top'].set(linewidth=0.5)
            i += 1

        plt.show()

    @staticmethod
    def show_images_in_add_axes(row=4, col=5, images=None):
        """
        show images in axes by fig.add_axes(rect)
        set axes by rect = [left, bottom, width, height]
        difficult to do
        """
        if not images:
            images = np.random.random([row*col, 512, 512])

        fig = plt.figure()
        for i in range(row):
            for j in range(col):
                left, bottom = i*1/4, j*1/5
                ax = fig.add_axes((left, bottom, 1/4, 1/5))     # [left, bottom, width, height]
                images[i*4+j, 0:100, 0:100] = (i*4*5 + j*10)/256
                ax.imshow(images[i*4 + j, :, :])
                ax.set_frame_on(False)
                ax.xaxis.set_visible(False)
                ax.yaxis.set_visible(False)
                ax.set_xticks([])
                ax.set_yticks([])
                # ax.set(xlim=[0, 1], ylim=[0, 1])
        plt.tight_layout(pad=1, h_pad=10, w_pad=0)
        plt.subplots_adjust(wspace=-5, hspace=0.5)
        plt.show()

    @staticmethod
    def show_images_in_axes_flat(row=4, col=5, images=None):
        fig, axs = plt.subplots(
            row, col,
            # figsize=(6, 4),
            subplot_kw={'xticks': [], 'yticks': []}
        )
        for i, ax in enumerate(axs.flat):
            ax.imshow(images[i], cmap='gray')
        plt.subplots_adjust(wspace=0, hspace=0)
        plt.tight_layout(pad=0, h_pad=0, w_pad=0)
        plt.show()

    @staticmethod
    def show_images_each_axes(fname=None, count=6, row=2, col=3):
        images = [plt.imread(fname+'/img{:03d}.jpg'.format(j+1)) for j in range(count)]
        plt.figure('images-1')
        for j in range(count):
            plt.subplot('{}{}{}'.format(row, col, j+1))
            # data = plt.imread(fname+'/img{:03d}.jpg'.format(j+1))
            plt.imshow(images[j])

        plt.figure('images-2')
        for j in range(count):
            plt.subplot('{}{}{}'.format(row, col, j+1))
            plt.imshow(images[j])
            plt.xticks([])
            plt.yticks([])


    @staticmethod
    def show_images_single_axes(fname=None, count=6, row=2, col=3):
        import cv2

        images = [plt.imread(fname+'/img{:03d}.jpg'.format(j+1)) for j in range(count)]
        for j, img in enumerate(images):
            # print(img.shape)
            # print(img[0, 0, 0:3])
            if img.shape[2] > 3:
                images[j] = img[:, :, 0:3]
            if img[0, 0, 0] > 1:
                images[j] = img / 255
            # plt.figure('test'+str(j))
            # plt.imshow(img)

        width, height = images[0].shape[0:2][::-1]
        imgall = None
        for r in range(row):
            imgrow = cv2.resize(images[r*col], (width, height))
            for c in range(1, col):
                img = cv2.resize(images[r*col+c], (width, height))
                imgrow = np.concatenate((imgrow, img), axis=1)
            imgall = imgrow if imgall is None else np.concatenate((imgall, imgrow), axis=0)

        plt.figure('images-all')
        plt.imshow(imgall)


class DemoTransform:

    def annotate_data_display_coordination(self):
        """
        show data and display coordination by using transform object
        from Matplotlib Tutorial Example
        """
        x = np.arange(0, 10, 0.005)
        y = np.exp(-x / 2.) * np.sin(2 * np.pi * x)

        fig = plt.figure()
        ax = fig.add_subplot(111)
        ax.plot(x, y)
        ax.set_xlim(0, 10)
        ax.set_ylim(-1, 1)

        xdata, ydata = 5, 0
        xdisplay, ydisplay = ax.transData.transform_point((xdata, ydata))

        bbox = dict(boxstyle="round", fc="0.8")
        arrowprops = dict(
            arrowstyle="->",
            connectionstyle="angle,angleA=0,angleB=90,rad=10")

        offset = 72
        ax.annotate('data = (%.1f, %.1f)' % (xdata, ydata),
                    (xdata, ydata), xytext=(-2 * offset, offset), textcoords='offset points',
                    bbox=bbox, arrowprops=arrowprops)

        disp = ax.annotate('display = (%.1f, %.1f)' % (xdisplay, ydisplay),
                           (xdisplay, ydisplay), xytext=(0.5 * offset, -offset),
                           xycoords='figure pixels',
                           textcoords='offset points',
                           bbox=bbox, arrowprops=arrowprops)
